UNPKG

@babylonjs/loaders

Version:

For usage documentation please visit https://doc.babylonjs.com/features/featuresDeepDive/importers/loadingFileTypes/.

1,248 lines 49.5 kB
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.js"; import { MultiplyTexturesAsync, LerpTexturesAsync, CreateTextureWithFactorOperand, TextureChannel, TextureColorSpace, InvertTextureAsync, ExtractChannelAsync, ChannelMask, ExtractMaxChannelAsync, } from "@babylonjs/core/Materials/Textures/textureProcessor.js"; /** * Material Loading Adapter for OpenPBR materials that provides a unified OpenPBR-like interface. */ export class OpenPBRMaterialLoadingAdapter { /** * Creates a new instance of the OpenPBRMaterialLoadingAdapter. * @param material - The OpenPBR material to adapt. */ constructor(material) { this._specWorkflow = false; this._diffuseTransmissionTint = Color3.White(); this._diffuseTransmissionTintTexture = null; this._material = material; } /** * Gets the underlying material */ get material() { return this._material; } /** * Whether the material should be treated as unlit */ get isUnlit() { return this._material.unlit; } /** * Sets whether the material should be treated as unlit */ set isUnlit(value) { this._material.unlit = value; } // ======================================== // CULLING PROPERTIES // ======================================== /** * Sets whether back face culling is enabled. * @param value True to enable back face culling */ set backFaceCulling(value) { this._material.backFaceCulling = value; } /** * Gets whether back face culling is enabled. * @returns True if back face culling is enabled */ get backFaceCulling() { return this._material.backFaceCulling; } /** * Sets whether two-sided lighting is enabled. * @param value True to enable two-sided lighting */ set twoSidedLighting(value) { this._material.twoSidedLighting = value; } /** * Gets whether two-sided lighting is enabled. * @returns True if two-sided lighting is enabled */ get twoSidedLighting() { return this._material.twoSidedLighting; } // ======================================== // ALPHA PROPERTIES // ======================================== /** * Sets the alpha cutoff value for alpha testing. * Note: OpenPBR doesn't have a direct equivalent, so this is a no-op. * @param value The alpha cutoff threshold (ignored for OpenPBR) */ set alphaCutOff(value) { this._material.alphaCutOff = value; } /** * Gets the alpha cutoff value. * @returns Default value of 0.5 (OpenPBR doesn't support this directly) */ get alphaCutOff() { return this._material.alphaCutOff; } /** * Sets whether to use alpha from the base color texture. * Note: OpenPBR handles this differently through the baseColorTexture alpha channel. * @param value True to use alpha from base color texture (handled automatically in OpenPBR) */ set useAlphaFromBaseColorTexture(value) { this._material._useAlphaFromBaseColorTexture = value; } /** * Gets whether alpha is used from the base color texture. * @returns True if alpha is used from the base color texture */ get useAlphaFromBaseColorTexture() { return this._material._useAlphaFromBaseColorTexture; } /** * Gets whether the transparency is treated as alpha coverage. */ get transparencyAsAlphaCoverage() { // OpenPBR doesn't support treating transparency as alpha coverage. return false; } /** * Sets/Gets whether the transparency is treated as alpha coverage */ set transparencyAsAlphaCoverage(value) { // OpenPBR doesn't support treating transparency as alpha coverage. } // ======================================== // BASE PARAMETERS // ======================================== /** * Sets the base color of the OpenPBR material. * @param value The base color as a Color3 */ set baseColor(value) { this._material.baseColor = value; } /** * Gets the base color of the OpenPBR material. * @returns The base color as a Color3 */ get baseColor() { return this._material.baseColor; } /** * Sets the base color texture of the OpenPBR material. * @param value The base color texture or null */ set baseColorTexture(value) { this._material.baseColorTexture = value; } /** * Gets the base color texture of the OpenPBR material. * @returns The base color texture or null */ get baseColorTexture() { return this._material.baseColorTexture; } /** * Sets the base diffuse roughness of the OpenPBR material. * @param value The diffuse roughness value (0-1) */ set baseDiffuseRoughness(value) { this._material.baseDiffuseRoughness = value; } /** * Gets the base diffuse roughness of the OpenPBR material. * @returns The diffuse roughness value (0-1) */ get baseDiffuseRoughness() { return this._material.baseDiffuseRoughness; } /** * Sets the base diffuse roughness texture of the OpenPBR material. * @param value The diffuse roughness texture or null */ set baseDiffuseRoughnessTexture(value) { this._material.baseDiffuseRoughnessTexture = value; } /** * Gets the base diffuse roughness texture of the OpenPBR material. * @returns The diffuse roughness texture or null */ get baseDiffuseRoughnessTexture() { return this._material.baseDiffuseRoughnessTexture; } /** * Sets the base metalness value of the OpenPBR material. * @param value The metalness value (0-1) */ set baseMetalness(value) { this._material.baseMetalness = value; } /** * Gets the base metalness value of the OpenPBR material. * @returns The metalness value (0-1) */ get baseMetalness() { return this._material.baseMetalness; } /** * Sets the base metalness texture of the OpenPBR material. * @param value The metalness texture or null */ set baseMetalnessTexture(value) { this._material.baseMetalnessTexture = value; } /** * Gets the base metalness texture of the OpenPBR material. * @returns The metalness texture or null */ get baseMetalnessTexture() { return this._material.baseMetalnessTexture; } /** * Sets whether to use roughness from the metallic texture's green channel. * @param value True to use green channel for roughness */ set useRoughnessFromMetallicTextureGreen(value) { this._material._useRoughnessFromMetallicTextureGreen = value; } /** * Sets whether to use metalness from the metallic texture's blue channel. * @param value True to use blue channel for metalness */ set useMetallicFromMetallicTextureBlue(value) { this._material._useMetallicFromMetallicTextureBlue = value; } // ======================================== // SPECULAR PARAMETERS // ======================================== /** * Configures specular properties for OpenPBR material. * @param _enableEdgeColor Whether to enable edge color support (ignored for OpenPBR) */ enableSpecularEdgeColor(_enableEdgeColor = false) { // OpenPBR already supports edge color natively, no configuration needed } configureSpecularGlossiness() { this._specWorkflow = true; } /** * Sets the specular weight of the OpenPBR material. * @param value The specular weight value (0-1) */ set specularWeight(value) { this._material.specularWeight = value; } /** * Gets the specular weight of the OpenPBR material. * @returns The specular weight value (0-1) */ get specularWeight() { return this._material.specularWeight; } /** * Sets the specular weight texture of the OpenPBR material. * If the same texture is used for specular color, optimizes by using alpha channel for weight. * @param value The specular weight texture or null */ set specularWeightTexture(value) { if (this._material.specularColorTexture === value) { this._material.specularWeightTexture = null; this._material._useSpecularWeightFromSpecularColorTexture = true; this._material._useSpecularWeightFromAlpha = true; } else { this._material.specularWeightTexture = value; } } /** * Gets the specular weight texture of the OpenPBR material. * @returns The specular weight texture or null */ get specularWeightTexture() { return this._material.specularWeightTexture; } /** * Sets the specular color of the OpenPBR material. * @param value The specular color as a Color3 */ set specularColor(value) { this._material.specularColor = value; } /** * Gets the specular color of the OpenPBR material. * @returns The specular color as a Color3 */ get specularColor() { return this._material.specularColor; } /** * Sets the specular color texture of the OpenPBR material. * If the same texture is used for specular weight, optimizes by using alpha channel for weight. * @param value The specular color texture or null */ set specularColorTexture(value) { this._material.specularColorTexture = value; if (this._material.specularWeightTexture === this._material.specularColorTexture) { this._material.specularWeightTexture = null; this._material._useSpecularWeightFromSpecularColorTexture = true; this._material._useSpecularWeightFromAlpha = true; } } /** * Gets the specular color texture of the OpenPBR material. * @returns The specular color texture or null */ get specularColorTexture() { return this._material.specularColorTexture; } /** * Sets the specular roughness of the OpenPBR material. * @param value The roughness value (0-1) */ set specularRoughness(value) { this._material.specularRoughness = value; } /** * Gets the specular roughness of the OpenPBR material. * @returns The roughness value (0-1) */ get specularRoughness() { return this._material.specularRoughness; } /** * Sets the specular roughness texture of the OpenPBR material. * @param value The roughness texture or null */ set specularRoughnessTexture(value) { this._material.specularRoughnessTexture = value; } /** * Gets the specular roughness texture of the OpenPBR material. * @returns The roughness texture or null */ get specularRoughnessTexture() { return this._material.specularRoughnessTexture; } /** * Sets the specular index of refraction (IOR) of the OpenPBR material. * @param value The IOR value */ set specularIor(value) { this._material.specularIor = value; } /** * Gets the specular index of refraction (IOR) of the OpenPBR material. * @returns The IOR value */ get specularIor() { return this._material.specularIor; } /** * Sets the glossiness (inverted roughness) of the OpenPBR material. */ set glossiness(value) { this._material.specularRoughness = Math.max(1.0 - value, 0.0); } get glossiness() { return 1.0 - this._material.specularRoughness; } // ======================================== // EMISSION PARAMETERS // ======================================== /** * Sets the emission color of the OpenPBR material. * @param value The emission color as a Color3 */ set emissionColor(value) { this._material.emissionColor = value; } /** * Gets the emission color of the OpenPBR material. * @returns The emission color as a Color3 */ get emissionColor() { return this._material.emissionColor; } /** * Sets the emission luminance of the OpenPBR material. * @param value The emission luminance value */ set emissionLuminance(value) { this._material.emissionLuminance = value; } /** * Gets the emission luminance of the OpenPBR material. * @returns The emission luminance value */ get emissionLuminance() { return this._material.emissionLuminance; } /** * Sets the emission color texture of the OpenPBR material. * @param value The emission texture or null */ set emissionColorTexture(value) { this._material.emissionColorTexture = value; } /** * Gets the emission color texture of the OpenPBR material. * @returns The emission texture or null */ get emissionColorTexture() { return this._material.emissionColorTexture; } // ======================================== // AMBIENT OCCLUSION // ======================================== /** * Sets the ambient occlusion texture of the OpenPBR material. * @param value The ambient occlusion texture or null */ set ambientOcclusionTexture(value) { this._material.ambientOcclusionTexture = value; } /** * Gets the ambient occlusion texture of the OpenPBR material. * @returns The ambient occlusion texture or null */ get ambientOcclusionTexture() { return this._material.ambientOcclusionTexture; } /** * Sets the ambient occlusion texture strength by modifying the texture's level. * @param value The strength value (typically 0-1) */ set ambientOcclusionTextureStrength(value) { const texture = this._material.ambientOcclusionTexture; if (texture) { texture.level = value; } } /** * Gets the ambient occlusion texture strength from the texture's level property. * @returns The strength value, defaults to 1.0 if no texture or level is set */ get ambientOcclusionTextureStrength() { const texture = this._material.ambientOcclusionTexture; return texture?.level ?? 1.0; } // ======================================== // COAT PARAMETERS // ======================================== /** * Configures coat parameters for OpenPBR material. * OpenPBR coat is already built-in, so no configuration is needed. */ configureCoat() { // OpenPBR coat is already built-in, no configuration needed } /** * Sets the coat weight of the OpenPBR material. * @param value The coat weight value (0-1) */ set coatWeight(value) { this._material.coatWeight = value; } /** * Gets the coat weight of the OpenPBR material. * @returns The coat weight value (0-1) */ get coatWeight() { return this._material.coatWeight; } /** * Sets the coat weight texture of the OpenPBR material. * @param value The coat weight texture or null */ set coatWeightTexture(value) { this._material.coatWeightTexture = value; } /** * Gets the coat weight texture of the OpenPBR material. * @returns The coat weight texture or null */ get coatWeightTexture() { return this._material.coatWeightTexture; } /** * Sets the coat color of the OpenPBR material. * @param value The coat color as a Color3 */ set coatColor(value) { this._material.coatColor = value; } /** * Gets the coat color of the OpenPBR material. */ get coatColor() { return this._material.coatColor; } /** * Sets the coat color texture of the OpenPBR material. * @param value The coat color texture or null */ set coatColorTexture(value) { this._material.coatColorTexture = value; } /** * Sets the coat roughness of the OpenPBR material. * @param value The coat roughness value (0-1) */ set coatRoughness(value) { this._material.coatRoughness = value; } /** * Gets the coat roughness of the OpenPBR material. * @returns The coat roughness value (0-1) */ get coatRoughness() { return this._material.coatRoughness; } /** * Sets the coat roughness texture of the OpenPBR material. * @param value The coat roughness texture or null */ set coatRoughnessTexture(value) { this._material.coatRoughnessTexture = value; if (value) { this._material._useCoatRoughnessFromGreenChannel = true; } } /** * Gets the coat roughness texture of the OpenPBR material. * @returns The coat roughness texture or null */ get coatRoughnessTexture() { return this._material.coatRoughnessTexture; } /** * Sets the coat index of refraction (IOR) of the OpenPBR material. */ set coatIor(value) { this._material.coatIor = value; } get coatIor() { return this._material.coatIor; } /** * Sets the coat darkening value of the OpenPBR material. * @param value The coat darkening value */ set coatDarkening(value) { this._material.coatDarkening = value; } get coatDarkening() { return this._material.coatDarkening; } /** * Sets the coat darkening texture (OpenPBR: coatDarkeningTexture, no PBR equivalent) */ set coatDarkeningTexture(value) { this._material.coatDarkeningTexture = value; } /** * Sets the coat roughness anisotropy. * TODO: Implementation pending OpenPBR coat anisotropy feature availability. * @param value The coat anisotropy intensity value */ set coatRoughnessAnisotropy(value) { this._material.coatRoughnessAnisotropy = value; } /** * Gets the coat roughness anisotropy. * TODO: Implementation pending OpenPBR coat anisotropy feature availability. * @returns Currently returns 0 as coat anisotropy is not yet available */ get coatRoughnessAnisotropy() { return this._material.coatRoughnessAnisotropy; } /** * Sets the coat tangent angle for anisotropy. * TODO: Implementation pending OpenPBR coat anisotropy feature availability. * @param value The coat anisotropy rotation angle in radians */ set geometryCoatTangentAngle(value) { this._material.geometryCoatTangentAngle = value; } /** * Sets the coat tangent texture for anisotropy. * TODO: Implementation pending OpenPBR coat anisotropy feature availability. * @param value The coat anisotropy texture or null */ set geometryCoatTangentTexture(value) { this._material.geometryCoatTangentTexture = value; if (value) { this._material._useCoatRoughnessAnisotropyFromTangentTexture = true; } } /** * Gets the coat tangent texture for anisotropy. * TODO: Implementation pending OpenPBR coat anisotropy feature availability. * @returns Currently returns null as coat anisotropy is not yet available */ get geometryCoatTangentTexture() { return this._material.geometryCoatTangentTexture; } // ======================================== // TRANSMISSION LAYER // ======================================== /** * Configures transmission for OpenPBR material. */ configureTransmission() { // Material is thin-walled until otherwise specified by the glTF volume extension. this._material.geometryThinWalled = 1.0; this._material.transmissionDepth = 0.0; } /** * Sets the transmission weight. * @param value The transmission weight value (0-1) */ set transmissionWeight(value) { this._material.transmissionWeight = value; } /** * Sets the transmission weight texture. * @param value The transmission weight texture or null */ set transmissionWeightTexture(value) { this._material.transmissionWeightTexture = value; } get transmissionWeightTexture() { return this._material.transmissionWeightTexture; } /** * Gets the transmission weight. * @returns Currently returns 0 as transmission is not yet available */ get transmissionWeight() { return this._material.transmissionWeight; } /** * Sets the transmission scatter coefficient. * @param value The scatter coefficient as a Vector3 */ set transmissionScatter(value) { this._material.transmissionScatter = value; } /** * Gets the transmission scatter coefficient. * @returns The scatter coefficient as a Vector3 */ get transmissionScatter() { return this._material.transmissionScatter; } /** * Sets the transmission scatter texture. * @param value The transmission scatter texture or null */ set transmissionScatterTexture(value) { this._material.transmissionScatterTexture = value; } /** * Gets the transmission scatter texture. * @returns The transmission scatter texture or null */ get transmissionScatterTexture() { return this._material.transmissionScatterTexture; } /** * Sets the transmission scattering anisotropy. * @param value The anisotropy intensity value (-1 to 1) */ set transmissionScatterAnisotropy(value) { this._material.transmissionScatterAnisotropy = value; } /** * Sets the transmission dispersion Abbe number. * @param value The Abbe number value */ set transmissionDispersionAbbeNumber(value) { this._material.transmissionDispersionAbbeNumber = value; } /** * Sets the transmission dispersion scale. * @param value The dispersion scale value */ set transmissionDispersionScale(value) { this._material.transmissionDispersionScale = value; } /** * Sets the attenuation distance. * @param value The attenuation distance value */ set transmissionDepth(value) { // If the value is being set to the default max value, and the current transmission depth is 0, // we assume that attenuation color isn't used and keep it at 0 to allow // us to use constant transmission color to handle glTF's surface tint from base color. if (value !== Number.MAX_VALUE || this._material.transmissionDepth !== 0) { this._material.transmissionDepth = value; } else { this._material.transmissionDepth = 0; } } /** * Gets the attenuation distance. */ get transmissionDepth() { return this._material.transmissionDepth; } /** * Sets the attenuation color. * @param value The attenuation color as a Color3 */ set transmissionColor(value) { // Only set the transmission color if it's not white (default) // This allows us to retain the base color as the transmission color, // if that was previously set. if (!value.equals(Color3.White())) { this._material.transmissionColor = value; } } /** * Gets the attenuation color. */ get transmissionColor() { return this._material.transmissionColor; } /** * Gets the refraction background texture * @returns The refraction background texture or null */ get refractionBackgroundTexture() { return this._material.backgroundRefractionTexture; } /** * Sets the refraction background texture * @param value The refraction background texture or null */ set refractionBackgroundTexture(value) { this._material.backgroundRefractionTexture = value; } // ======================================== // VOLUME PROPERTIES // ======================================== /** * Configures volume properties for OpenPBR material. */ configureVolume() { // If we're configuring volume, we assume the material is not thin-walled (i.e. it's volumetric). this._material.geometryThinWalled = 0.0; } /** * Sets whether the material is thin-walled (i.e. non-volumetric) or not. */ set geometryThinWalled(value) { this._material.geometryThinWalled = value ? 1.0 : 0.0; } /** * Gets whether the material is thin-walled (i.e. non-volumetric) or not. */ get geometryThinWalled() { return this._material.geometryThinWalled ? true : false; } /** * Sets the thickness texture. * @param value The thickness texture or null */ set volumeThicknessTexture(value) { this._material.geometryThicknessTexture = value; this._material._useGeometryThicknessFromGreenChannel = true; } /** * Sets the thickness factor. * @param value The thickness value */ set volumeThickness(value) { this._material.geometryThickness = value; } // ======================================== // SUBSURFACE PROPERTIES (Subsurface Scattering) // ======================================== /** * Configures subsurface properties for PBR material */ configureSubsurface() { // glTF diffuse transmission is thin-walled (before volume extension is applied) will map to the subsurface slab and, without a this._material.geometryThinWalled = 1.0; this._material.subsurfaceScatterAnisotropy = 1.0; } /** * Sets the subsurface weight */ set subsurfaceWeight(value) { this._material.subsurfaceWeight = value; } get subsurfaceWeight() { return this._material.subsurfaceWeight; } /** * Sets the subsurface weight texture */ set subsurfaceWeightTexture(value) { this._material.subsurfaceWeightTexture = value; this._material._useSubsurfaceWeightFromTextureAlpha = true; } get subsurfaceWeightTexture() { return this._material.subsurfaceWeightTexture; } /** * Sets the subsurface color. * @param value The subsurface tint color as a Color3 */ set subsurfaceColor(value) { this._material.subsurfaceColor = value; } /** * Sets the subsurface color texture. * @param value The subsurface tint texture or null */ set subsurfaceColorTexture(value) { this._material.subsurfaceColorTexture = value; } /** * Sets the diffuse transmission tint of the material */ set diffuseTransmissionTint(value) { this._diffuseTransmissionTint = value; } /** * Gets the diffuse transmission tint of the material */ get diffuseTransmissionTint() { return this._diffuseTransmissionTint; } /** * Sets the diffuse transmission tint texture of the material */ set diffuseTransmissionTintTexture(value) { this._diffuseTransmissionTintTexture = value; } /** * Gets the subsurface radius for subsurface scattering. * subsurfaceRadiusScale * subsurfaceRadius gives the mean free path per color channel. */ get subsurfaceRadius() { return this._material.subsurfaceRadius; } /** * Sets the subsurface radius for subsurface scattering. * subsurfaceRadiusScale * subsurfaceRadius gives the mean free path per color channel. * @param value The subsurface radius value */ set subsurfaceRadius(value) { this._material.subsurfaceRadius = value; } /** * Gets the subsurface radius scale for subsurface scattering. * subsurfaceRadiusScale * subsurfaceRadius gives the mean free path per color channel. */ get subsurfaceRadiusScale() { return this._material.subsurfaceRadiusScale; } /** * Sets the subsurface radius scale for subsurface scattering. * subsurfaceRadiusScale * subsurfaceRadius gives the mean free path per color channel. * @param value The subsurface radius scale as a Color3 */ set subsurfaceRadiusScale(value) { this._material.subsurfaceRadiusScale = value; } /** * Sets the subsurface scattering anisotropy. * @param value The anisotropy intensity value */ set subsurfaceScatterAnisotropy(value) { this._material.subsurfaceScatterAnisotropy = value; } /** * Does this material have a translucent surface (i.e. either transmission or subsurface)? * @returns True if the material is translucent, false otherwise */ isTranslucent() { return this.transmissionWeight > 0 || this.subsurfaceWeight > 0; } // ======================================== // FUZZ LAYER (Sheen) // ======================================== /** * Configures fuzz for OpenPBR. * Enables fuzz and sets up proper configuration. */ configureFuzz() { // Currently no setup to do for OpenPBR } /** * Sets the fuzz weight. * @param value The fuzz weight value */ set fuzzWeight(value) { this._material.fuzzWeight = value; } /** * Sets the fuzz weight texture. * @param value The fuzz weight texture or null */ set fuzzWeightTexture(value) { this._material.fuzzWeightTexture = value; } /** * Sets the fuzz color. * @param value The fuzz color as a Color3 */ set fuzzColor(value) { this._material.fuzzColor = value; } /** * Sets the fuzz color texture. * @param value The fuzz color texture or null */ set fuzzColorTexture(value) { this._material.fuzzColorTexture = value; } /** * Sets the fuzz roughness. * @param value The fuzz roughness value (0-1) */ set fuzzRoughness(value) { this._material.fuzzRoughness = value; } /** * Sets the fuzz roughness texture. * @param value The fuzz roughness texture or null */ set fuzzRoughnessTexture(value) { this._material.fuzzRoughnessTexture = value; this._material._useFuzzRoughnessFromTextureAlpha = true; } // ======================================== // ANISOTROPY // ======================================== /** * Sets the specular roughness anisotropy of the OpenPBR material. * @param value The anisotropy intensity value */ set specularRoughnessAnisotropy(value) { this._material.specularRoughnessAnisotropy = value; } /** * Gets the specular roughness anisotropy of the OpenPBR material. * @returns The anisotropy intensity value */ get specularRoughnessAnisotropy() { return this._material.specularRoughnessAnisotropy; } /** * Sets the anisotropy rotation angle. * @param value The anisotropy rotation angle in radians */ set geometryTangentAngle(value) { this._material.geometryTangentAngle = value; } /** * Sets the geometry tangent texture for anisotropy. * Automatically enables using anisotropy from the tangent texture. * @param value The anisotropy texture or null */ set geometryTangentTexture(value) { this._material.geometryTangentTexture = value; this._material._useSpecularRoughnessAnisotropyFromTangentTexture = true; } /** * Gets the geometry tangent texture for anisotropy. * @returns The anisotropy texture or null */ get geometryTangentTexture() { return this._material.geometryTangentTexture; } /** * Configures glTF-style anisotropy for the OpenPBR material. * @param useGltfStyle Whether to use glTF-style anisotropy */ configureGltfStyleAnisotropy(useGltfStyle = true) { this._material._useGltfStyleAnisotropy = useGltfStyle; } // ======================================== // THIN FILM IRIDESCENCE // ======================================== /** * Sets the thin film weight. * @param value The thin film weight value */ set thinFilmWeight(value) { this._material.thinFilmWeight = value; } /** * Sets the thin film IOR. * @param value The thin film IOR value */ set thinFilmIor(value) { this._material.thinFilmIor = value; } /** * Sets the thin film thickness minimum. * @param value The minimum thickness value in nanometers */ set thinFilmThicknessMinimum(value) { this._material.thinFilmThicknessMin = value / 1000.0; // Convert to micrometers for OpenPBR } /** * Sets the thin film thickness maximum. * @param value The maximum thickness value in nanometers */ set thinFilmThicknessMaximum(value) { this._material.thinFilmThickness = value / 1000.0; // Convert to micrometers for OpenPBR } /** * Sets the thin film weight texture. * @param value The thin film weight texture or null */ set thinFilmWeightTexture(value) { this._material.thinFilmWeightTexture = value; } /** * Sets the thin film thickness texture. * @param value The thin film thickness texture or null */ set thinFilmThicknessTexture(value) { this._material.thinFilmThicknessTexture = value; this._material._useThinFilmThicknessFromTextureGreen = true; } // ======================================== // UNLIT MATERIALS // ======================================== /** * Sets whether the OpenPBR material is unlit. * @param value True to make the material unlit */ set unlit(value) { this._material.unlit = value; } // ======================================== // GEOMETRY PARAMETERS // ======================================== /** * Sets the geometry opacity of the OpenPBR material. * @param value The opacity value (0-1) */ set geometryOpacity(value) { this._material.geometryOpacity = value; } /** * Gets the geometry opacity of the OpenPBR material. * @returns The opacity value (0-1) */ get geometryOpacity() { return this._material.geometryOpacity; } /** * Sets the geometry normal texture of the OpenPBR material. * @param value The normal texture or null */ set geometryNormalTexture(value) { this._material.geometryNormalTexture = value; } /** * Gets the geometry normal texture of the OpenPBR material. * @returns The normal texture or null */ get geometryNormalTexture() { return this._material.geometryNormalTexture; } /** * Sets the normal map inversions for the OpenPBR material. * Note: OpenPBR may handle normal map inversions differently or may not need them. * @param invertX Whether to invert the normal map on the X axis (may be ignored) * @param invertY Whether to invert the normal map on the Y axis (may be ignored) */ setNormalMapInversions(invertX, invertY) { // OpenPBR handles normal map inversions differently or may not need them } /** * Sets the geometry coat normal texture of the OpenPBR material. * @param value The coat normal texture or null */ set geometryCoatNormalTexture(value) { this._material.geometryCoatNormalTexture = value; } /** * Gets the geometry coat normal texture of the OpenPBR material. * @returns The coat normal texture or null */ get geometryCoatNormalTexture() { return this._material.geometryCoatNormalTexture; } /** * Sets the geometry coat normal texture scale. * @param value The scale value for the coat normal texture */ set geometryCoatNormalTextureScale(value) { if (this._material.geometryCoatNormalTexture) { this._material.geometryCoatNormalTexture.level = value; } } /** * Finalizes material properties after all loading is complete. * @param loader The glTF loader; `loader._disposed` is polled between texture passes to bail early on dispose. */ async finalizeAsync(loader) { // Do final configuration for the material to handle any interactions/dependencies between properties that we had to defer until all properties were loaded. // If the material is volumetric, we may need to create a coat layer to handle the surface tint. if ((this._diffuseTransmissionTint && !this._diffuseTransmissionTint.equals(Color3.White())) || this._diffuseTransmissionTintTexture) { if (this._material.geometryThinWalled) { // Use the subsurface slab for surface tinting. this.subsurfaceColor = this._diffuseTransmissionTint; this.subsurfaceColorTexture = this._diffuseTransmissionTintTexture; } else { // Otherwise, we have volumetric attenuation so we need to use the coat layer to preserve the base color tinting of glTF. await this.copySurfaceToCoatAsync(loader, this.subsurfaceWeight, this.subsurfaceWeightTexture, TextureChannel.A, this._diffuseTransmissionTint, this._diffuseTransmissionTintTexture, true); if (loader._disposed) { return; } } } // If the material has transmission, we need to use the base color to tint the transmission. if (this.transmissionWeight > 0) { if (this._material.geometryThinWalled || this._material.transmissionDepth === 0) { // If the material is thin-walled or has no attenuation depth, we can use the base color as the transmission color directly. this._material.transmissionColor = this._material.baseColor; this._material.transmissionColorTexture = this._material.baseColorTexture; } else if (!this.baseColor.equals(Color3.White()) || this.baseColorTexture !== null) { // Otherwise, we have volumetric attenuation so we need to use the coat layer to preserve the base color tinting of glTF. await this.copySurfaceToCoatAsync(loader, this.transmissionWeight, this.transmissionWeightTexture, TextureChannel.R, this.baseColor, this.baseColorTexture, false); if (loader._disposed) { return; } } } if (this._specWorkflow) { // To convert from spec-gloss to OpenPBR, we'll grab the specular color's alpha channel (which contains glossiness) and // invert it to get roughness. 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); if (loader._disposed) { newRoughnessTexture.texture?.dispose(); return; } this.specularRoughnessTexture = newRoughnessTexture.texture; this.specularRoughness = newRoughnessTexture.factor ? newRoughnessTexture.factor.r : 1.0; // Metallic = max(linearize(specular).rgb). The specular texture is sRGB so we must // linearize it first (TextureColorSpace.SRGB). The factor is already linear per convention. // We store metallic as linear (no outputColorSpace) because it is a data/scalar value; // encoding it as sRGB would corrupt it when it is used as the lerp t below. 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); if (loader._disposed) { newMetallic.texture?.dispose(); return; } this.baseMetalnessTexture = newMetallic.texture; this.baseMetalness = newMetallic.factor ? newMetallic.factor.r : 1.0; // base_color = lerp(diffuse, specular, metallic). // Strip dispose before passing newMetallic as t — its texture is already owned by the // material (baseMetalnessTexture) and must not be released after the lerp pass. 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); if (loader._disposed) { newBaseColor.texture?.dispose(); return; } const oldBaseColorTexture = this.baseColorTexture; oldBaseColorTexture?.dispose(); this.baseColorTexture = newBaseColor.texture; this.baseColor = newBaseColor.factor ? new Color3(newBaseColor.factor.r, newBaseColor.factor.g, newBaseColor.factor.b) : Color3.White(); const oldSpecularColorTexture = this.specularColorTexture; oldSpecularColorTexture?.dispose(); this.specularColorTexture = null; } } async copySurfaceToCoatAsync(loader, weight, weightTexture, weightTextureChannel, color, colorTexture, diffuseTransmission = false) { // Blend coat properties using: // New coat will cover all areas that previously had coat or transmission. // new_coat_weight = max(weight, existing_coat_weight) // New coat color is the multiplication of the base color tint and the existing coat tint, each blended by their respective weights: // new_coat_color = lerp(white, existing_coat_color, existing_coat_weight) // * lerp(white, color, weight) // Snapshot the original coat properties before mutating them, so both lerps // use the pre-merge values (the first lerp blends the *existing* coat color // by the *existing* coat weight; we must not use the merged weight here). const origCoatWeight = this._material.coatWeight; const origCoatWeightTexture = this._material.coatWeightTexture; const origCoatColor = this._material.coatColor.clone(); const origCoatColorTexture = this._material.coatColorTexture; const origCoatNormalTexture = this._material.geometryCoatNormalTexture; const origCoatWeightCol4 = new Color4(origCoatWeight, origCoatWeight, origCoatWeight, origCoatWeight); const weightCol4 = new Color4(weight, weight, weight, weight); this.coatWeightTexture = null; this.coatWeight = 1.0; const results = await Promise.allSettled([ 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), 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), ]); const rejected = results.find((r) => r.status === "rejected"); if (rejected) { for (const r of results) { if (r.status === "fulfilled") { r.value.texture?.dispose(); } } throw rejected.reason; } const [lerpCoatColor, lerpSurfaceColor] = results.map((r) => r.value); if (loader._disposed) { lerpCoatColor.texture?.dispose(); lerpSurfaceColor.texture?.dispose(); return; } const newCoatColor = await MultiplyTexturesAsync("newCoatColor (" + this._material.name + ")", lerpCoatColor, lerpSurfaceColor, this._material.getScene(), TextureColorSpace.SRGB); if (loader._disposed) { newCoatColor.texture?.dispose(); return; } if (newCoatColor.texture) { this.coatColorTexture = newCoatColor.texture; this.coatColor = Color3.White(); } else if (newCoatColor.factor) { this.coatColorTexture = null; this.coatColor.fromArray([newCoatColor.factor.r, newCoatColor.factor.g, newCoatColor.factor.b]); } 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()); if (loader._disposed) { newCoatIor.texture?.dispose(); return; } this.coatIor = newCoatIor.factor ? newCoatIor.factor.r : this.coatIor; 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()); if (loader._disposed) { newCoatRoughness.texture?.dispose(); return; } this.coatRoughness = newCoatRoughness.factor ? newCoatRoughness.factor.r : 1.0; this.coatRoughnessTexture = newCoatRoughness.texture; 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()); if (loader._disposed) { newCoatDarkening.texture?.dispose(); return; } this.coatDarkening = newCoatDarkening.factor ? newCoatDarkening.factor.r : this.coatDarkening; if (diffuseTransmission) { 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()); if (loader._disposed) { newSpecularRoughness.texture?.dispose(); return; } this.specularRoughness = newSpecularRoughness.factor ? newSpecularRoughness.factor.r : 1.0; this.specularRoughnessTexture = newSpecularRoughness.texture; } if (origCoatNormalTexture || this.geometryNormalTexture) { 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()); if (loader._disposed) { newCoatNormal.texture?.dispose(); return; } if (newCoatNormal.texture) { this.geometryCoatNormalTexture = newCoatNormal.texture; } } } } //# sourceMappingURL=openpbrMaterialLoadingAdapter.js.map