diff --git a/packages/core/src/material/PBRMaterial.ts b/packages/core/src/material/PBRMaterial.ts index 2cd90bda3c..9b0d65ba30 100644 --- a/packages/core/src/material/PBRMaterial.ts +++ b/packages/core/src/material/PBRMaterial.ts @@ -1,4 +1,4 @@ -import { MathUtil, Vector3 } from "@galacean/engine-math"; +import { MathUtil, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; import { Engine } from "../Engine"; import { ShaderProperty } from "../shader"; import { Shader } from "../shader/Shader"; @@ -20,6 +20,11 @@ export class PBRMaterial extends PBRBaseMaterial { private _anisotropyRotation: number = 0; + private static _iridescenceInfoProp = ShaderProperty.getByName("material_IridescenceInfo"); + private static _iridescenceThicknessTextureProp = ShaderProperty.getByName("material_IridescenceThicknessTexture"); + private static _iridescenceTextureProp = ShaderProperty.getByName("material_IridescenceTexture"); + private _iridescenceRange = new Vector2(100, 400); + /** * Index Of Refraction. * @defaultValue `1.5` @@ -132,6 +137,91 @@ export class PBRMaterial extends PBRBaseMaterial { } } + /** + * The iridescence intensity factor, from 0.0 to 1.0. + * @defaultValue `0.0` + */ + get iridescence(): number { + return this.shaderData.getVector4(PBRMaterial._iridescenceInfoProp).x; + } + + set iridescence(value: number) { + value = Math.max(0, Math.min(1, value)); + const iridescenceInfo = this.shaderData.getVector4(PBRMaterial._iridescenceInfoProp); + if (!!iridescenceInfo.x !== !!value) { + if (value === 0) { + this.shaderData.disableMacro("MATERIAL_ENABLE_IRIDESCENCE"); + } else { + this.shaderData.enableMacro("MATERIAL_ENABLE_IRIDESCENCE"); + } + } + iridescenceInfo.x = value; + } + + /** + * The iridescence intensity texture, sampling red channel, and multiply 'iridescence'. + */ + get iridescenceTexture(): Texture2D { + return this.shaderData.getTexture(PBRMaterial._iridescenceTextureProp); + } + + set iridescenceTexture(value: Texture2D) { + this.shaderData.setTexture(PBRMaterial._iridescenceTextureProp, value); + + if (value) { + this.shaderData.enableMacro("MATERIAL_HAS_IRIDESCENCE_TEXTURE"); + } else { + this.shaderData.disableMacro("MATERIAL_HAS_IRIDESCENCE_TEXTURE"); + } + } + + /** + * The index of refraction of the dielectric thin-film layer, greater than or equal to 1.0. + * @defaultValue `1.3` + */ + get iridescenceIOR(): number { + return this.shaderData.getVector4(PBRMaterial._iridescenceInfoProp).y; + } + + set iridescenceIOR(value: number) { + const iridescenceInfo = this.shaderData.getVector4(PBRMaterial._iridescenceInfoProp); + iridescenceInfo.y = Math.max(value, 1.0); + } + + /** + * The range of iridescence thickness, x is minimum, y is maximum. + * @defaultValue `[100, 400]`. + */ + get iridescenceThicknessRange(): Vector2 { + return this._iridescenceRange; + } + + set iridescenceThicknessRange(value: Vector2) { + if (this._iridescenceRange !== value) { + this._iridescenceRange.copyFrom(value); + } + } + + /** + * The thickness texture of the thin-film layer, sampling green channel. + * @remarks + * If iridescenceThicknessTexture is defined, iridescence thickness between the 'iridescenceThicknessRange'. + * If iridescenceThicknessTexture is not defined, iridescence thickness will use only 'iridescenceThicknessRange.y'. + */ + get iridescenceThicknessTexture(): Texture2D { + return this.shaderData.getTexture(PBRMaterial._iridescenceThicknessTextureProp); + } + + set iridescenceThicknessTexture(value: Texture2D) { + this.shaderData.setTexture(PBRMaterial._iridescenceThicknessTextureProp, value); + + if (value) { + this.shaderData.enableMacro("MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE"); + } else { + this.shaderData.disableMacro("MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE"); + } + } + /** * Create a pbr metallic-roughness workflow material instance. * @param engine - Engine to which the material belongs @@ -144,6 +234,15 @@ export class PBRMaterial extends PBRBaseMaterial { shaderData.setFloat(PBRMaterial._roughnessProp, 1); shaderData.setFloat(PBRMaterial._iorProp, 1.5); shaderData.setVector3(PBRMaterial._anisotropyInfoProp, new Vector3(1, 0, 0)); + shaderData.setVector4(PBRMaterial._iridescenceInfoProp, new Vector4(0, 1.3, 100, 400)); + // @ts-ignore + this._iridescenceRange._onValueChanged = this._onIridescenceRangeChanged.bind(this); + } + + private _onIridescenceRangeChanged(): void { + const iridescenceInfo = this.shaderData.getVector4(PBRMaterial._iridescenceInfoProp); + iridescenceInfo.z = this._iridescenceRange.x; + iridescenceInfo.w = this._iridescenceRange.y; } /** diff --git a/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts b/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts index f2a3720e8d..b0ee1c536a 100644 --- a/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts +++ b/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts @@ -26,11 +26,11 @@ export interface IKHRLightsPunctual { * Interfaces from the KHR_materials_clearcoat extension */ export interface IKHRMaterialsClearcoat { - clearcoatFactor: number; - clearcoatTexture: ITextureInfo; - clearcoatRoughnessFactor: number; - clearcoatRoughnessTexture: ITextureInfo; - clearcoatNormalTexture: IMaterialNormalTextureInfo; + clearcoatFactor?: number; + clearcoatTexture?: ITextureInfo; + clearcoatRoughnessFactor?: number; + clearcoatRoughnessTexture?: ITextureInfo; + clearcoatNormalTexture?: IMaterialNormalTextureInfo; } /** @@ -176,6 +176,18 @@ export interface IGalaceanAnimation { }[]; } +/** + * Interfaces from the KHR_materials_iridescence extension + */ +export interface IKHRMaterialsIridescence { + iridescenceFactor?: number; + iridescenceTexture?: ITextureInfo; + iridescenceIor?: number; + iridescenceThicknessMinimum?: number; + iridescenceThicknessMaximum?: number; + iridescenceThicknessTexture?: ITextureInfo; +} + export type GLTFExtensionSchema = | IKHRLightsPunctual_Light | IKHRMaterialsClearcoat @@ -194,4 +206,5 @@ export type GLTFExtensionSchema = | IKHRXmp | IKHRXmp_Node | IGalaceanAnimation + | IKHRMaterialsIridescence | Object; diff --git a/packages/loader/src/gltf/extensions/KHR_materials_iridescence.ts b/packages/loader/src/gltf/extensions/KHR_materials_iridescence.ts new file mode 100644 index 0000000000..6b7b1cb95d --- /dev/null +++ b/packages/loader/src/gltf/extensions/KHR_materials_iridescence.ts @@ -0,0 +1,39 @@ +import { PBRMaterial, Texture2D } from "@galacean/engine-core"; +import { GLTFMaterialParser } from "../parser/GLTFMaterialParser"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRMaterialsIridescence } from "./GLTFExtensionSchema"; + +@registerGLTFExtension("KHR_materials_iridescence", GLTFExtensionMode.AdditiveParse) +class KHR_materials_iridescence extends GLTFExtensionParser { + override additiveParse(context: GLTFParserContext, material: PBRMaterial, schema: IKHRMaterialsIridescence): void { + const { + iridescenceFactor = 0, + iridescenceTexture, + iridescenceIor = 1.3, + iridescenceThicknessMinimum = 100, + iridescenceThicknessMaximum = 400, + iridescenceThicknessTexture + } = schema; + + material.iridescence = iridescenceFactor; + material.iridescenceIOR = iridescenceIor; + material.iridescenceThicknessRange.set(iridescenceThicknessMinimum, iridescenceThicknessMaximum); + + if (iridescenceTexture) { + GLTFMaterialParser._checkOtherTextureTransform(iridescenceTexture, "Iridescence texture"); + + context.get(GLTFParserType.Texture, iridescenceTexture.index).then((texture) => { + material.iridescenceTexture = texture; + }); + } + if (iridescenceThicknessTexture) { + GLTFMaterialParser._checkOtherTextureTransform(iridescenceThicknessTexture, "IridescenceThickness texture"); + + context.get(GLTFParserType.Texture, iridescenceThicknessTexture.index).then((texture) => { + material.iridescenceThicknessTexture = texture; + }); + } + } +} diff --git a/packages/loader/src/gltf/extensions/index.ts b/packages/loader/src/gltf/extensions/index.ts index bce13d34c5..1cacdf00a0 100644 --- a/packages/loader/src/gltf/extensions/index.ts +++ b/packages/loader/src/gltf/extensions/index.ts @@ -15,6 +15,7 @@ import "./GALACEAN_materials_remap"; import "./GALACEAN_animation_event"; import "./EXT_meshopt_compression"; import "./KHR_materials_anisotropy"; +import "./KHR_materials_iridescence"; import "./EXT_texture_webp"; export { GLTFExtensionParser, GLTFExtensionMode } from "./GLTFExtensionParser";