diff --git a/packages/dev/buildTools/src/addJSToCompiledFiles.ts b/packages/dev/buildTools/src/addJSToCompiledFiles.ts index 6e55dbb546a..686a7ef5383 100644 --- a/packages/dev/buildTools/src/addJSToCompiledFiles.ts +++ b/packages/dev/buildTools/src/addJSToCompiledFiles.ts @@ -8,6 +8,8 @@ function ProcessSource(sourceCode: string, forceMJS: boolean) { const extension = forceMJS ? ".mjs" : ".js"; return ( sourceCode + // replace imports from directories with index.js (mixins are generating them) + .replace(/import\("([./]+)"\)/g, `import("$1/index${extension}")`) // replace imports and exports with js extensions .replace(/((import|export).*["'](@babylonjs\/.*\/|\.{1,2}\/)((?!\.scss|\.svg|\.png|\.jpg).)*?)("|');/g, `$1${extension}$5;`) .replace(/((import|export)\(["']((@babylonjs\/.*\/|\.{1,2}\/)((?!\.scss|\.svg|\.png|\.jpg).)*?))(["'])\)/g, `$1${extension}$6)`) diff --git a/packages/dev/buildTools/src/generateDeclaration.ts b/packages/dev/buildTools/src/generateDeclaration.ts index 4d17d0a3849..162e73a9374 100644 --- a/packages/dev/buildTools/src/generateDeclaration.ts +++ b/packages/dev/buildTools/src/generateDeclaration.ts @@ -76,6 +76,9 @@ function GetModuleDeclaration( line = line.startsWith(" ") ? " //" + line.substring(3) : "// " + line; } + // replace type imports from directories with index (mixins are generating them) + line = line.replace(/import\("([./]+)"\)/g, `import("$1/index")`); + [ // Declaration /declare module ['"](.*)['"]/, @@ -85,7 +88,7 @@ function GetModuleDeclaration( / {4}module ['"](.*)['"]/, /^module ['"](\..*)['"]/, // Inlined Import - /import\(['"](.*)['"]/, + /import\(['"]([^'"]*)['"]/, // Side Effect Import /import ['"](.*)['"]/, ].forEach((regex) => { @@ -93,7 +96,9 @@ function GetModuleDeclaration( if (match) { if (match[1][0] === ".") { const newLocation = path.join(sourceDir, match[1]).replace(/\\/g, "/"); - line = line.replace(match[1], newLocation); + // replaceAll only avaialable by modifying the typescript lib + // which we prefered to not change for now + line = (line as any).replaceAll(match[1], newLocation); } else { let found = false; Object.keys(mapping).forEach((devPackageName) => { @@ -319,8 +324,8 @@ function GetPackageDeclaration( while (i < lines.length) { let line = lines[i]; - if (/import\("\.(.*)\)./g.test(line) && !/^declare type (.*) import/g.test(line)) { - line = line.replace(/import\((.*)\)./, ""); + if (/import\("\.([^)]*)\)./g.test(line) && !/^declare type (.*) import/g.test(line)) { + line = line.replace(/import\(([^)]*)\)./g, ""); } if (!line.includes("const enum") && !line.includes("=")) { diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index 8caad63d4e0..540ea120722 100644 --- a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts +++ b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, serializeAsVector3, serializeAsImageProcessingConfiguration } from "../../Misc/decorators"; +import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, serializeAsVector3 } from "../../Misc/decorators"; import { SmartArray } from "../../Misc/smartArray"; -import type { Observer } from "../../Misc/observable"; import { Logger } from "../../Misc/logger"; import type { Nullable, int, float } from "../../types"; import type { Scene } from "../../scene"; @@ -14,11 +13,9 @@ import type { Mesh } from "../../Meshes/mesh"; import type { IEffectCreationOptions } from "../../Materials/effect"; import { MaterialDefines } from "../../Materials/materialDefines"; import { PushMaterial } from "../../Materials/pushMaterial"; -import type { ColorCurves } from "../../Materials/colorCurves"; -import type { IImageProcessingConfigurationDefines } from "../../Materials/imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; -import { Texture } from "../../Materials/Textures/texture"; import type { RenderTargetTexture } from "../../Materials/Textures/renderTargetTexture"; import type { IShadowLight } from "../../Lights/shadowLight"; import { Constants } from "../../Engines/constants"; @@ -34,25 +31,33 @@ import { BindLights, BindLogDepth, BindTextureMatrix, + BindIBLParameters, + BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, + PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareUniformsAndSamplersList, + PrepareUniformsAndSamplersForIBL, + PrepareUniformLayoutForIBL, } from "../materialHelper.functions"; import { SerializationHelper } from "../../Misc/decorators.serialization"; import { ShaderLanguage } from "../shaderLanguage"; +import { ImageProcessingMixin } from "../imageProcessing"; + +class BackgroundMaterialDefinesBase extends MaterialDefines {} /** * Background material defines definition. * @internal Mainly internal Use */ -class BackgroundMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +class BackgroundMaterialDefines extends ImageProcessingDefinesMixin(BackgroundMaterialDefinesBase) { /** * True if the diffuse texture is in use. */ @@ -135,23 +140,6 @@ class BackgroundMaterialDefines extends MaterialDefines implements IImageProcess */ public PROJECTED_GROUND = false; - public IMAGEPROCESSING = false; - public VIGNETTE = false; - public VIGNETTEBLENDMODEMULTIPLY = false; - public VIGNETTEBLENDMODEOPAQUE = false; - public TONEMAPPING = 0; - public CONTRAST = false; - public COLORCURVES = false; - public COLORGRADING = false; - public COLORGRADING3D = false; - public SAMPLER3DGREENDEPTH = false; - public SAMPLER3DBGRMAP = false; - public DITHER = false; - public IMAGEPROCESSINGPOSTPROCESS = false; - public SKIPFINALCOLORCLAMP = false; - public EXPOSURE = false; - public MULTIVIEW = false; - // Reflection. public REFLECTION = false; public REFLECTIONMAP_3D = false; @@ -202,11 +190,12 @@ class BackgroundMaterialDefines extends MaterialDefines implements IImageProcess } } +class BackgroundMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * Background material used to create an efficient environment around your scene. * #157MGZ: simple test */ -export class BackgroundMaterial extends PushMaterial { +export class BackgroundMaterial extends BackgroundMaterialBase { /** * Standard reflectance value at parallel view angle. */ @@ -454,168 +443,6 @@ export class BackgroundMaterial extends PushMaterial { @expandToProperty("_markAllSubMeshesAsLightsDirty") public shadowOnly: boolean = false; - /** - * Default configuration related to image processing available in the Background Material. - */ - @serializeAsImageProcessingConfiguration() - protected _imageProcessingConfiguration: ImageProcessingConfiguration; - - /** - * Keep track of the image processing observer to allow dispose and replace. - */ - private _imageProcessingObserver: Nullable> = null; - - /** - * Attaches a new image processing configuration to the PBR Material. - * @param configuration (if null the scene configuration will be use) - */ - protected _attachImageProcessingConfiguration(configuration: Nullable): void { - if (configuration === this._imageProcessingConfiguration) { - return; - } - - // Detaches observer. - if (this._imageProcessingConfiguration && this._imageProcessingObserver) { - this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); - } - - // Pick the scene configuration if needed. - if (!configuration) { - this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration; - } else { - this._imageProcessingConfiguration = configuration; - } - - // Attaches observer. - if (this._imageProcessingConfiguration) { - this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { - this._computePrimaryColorFromPerceptualColor(); - this._markAllSubMeshesAsImageProcessingDirty(); - }); - } - } - - /** - * Gets the image processing configuration used either in this material. - */ - public get imageProcessingConfiguration(): Nullable { - return this._imageProcessingConfiguration; - } - - /** - * Sets the Default image processing configuration used either in the this material. - * - * If sets to null, the scene one is in use. - */ - public set imageProcessingConfiguration(value: Nullable) { - this._attachImageProcessingConfiguration(value); - - // Ensure the effect will be rebuilt. - this._markAllSubMeshesAsTexturesDirty(); - } - - /** - * Gets whether the color curves effect is enabled. - */ - public get cameraColorCurvesEnabled(): boolean { - return (this.imageProcessingConfiguration).colorCurvesEnabled; - } - /** - * Sets whether the color curves effect is enabled. - */ - public set cameraColorCurvesEnabled(value: boolean) { - (this.imageProcessingConfiguration).colorCurvesEnabled = value; - } - - /** - * Gets whether the color grading effect is enabled. - */ - public get cameraColorGradingEnabled(): boolean { - return (this.imageProcessingConfiguration).colorGradingEnabled; - } - /** - * Gets whether the color grading effect is enabled. - */ - public set cameraColorGradingEnabled(value: boolean) { - (this.imageProcessingConfiguration).colorGradingEnabled = value; - } - - /** - * Gets whether tonemapping is enabled or not. - */ - public get cameraToneMappingEnabled(): boolean { - return this._imageProcessingConfiguration.toneMappingEnabled; - } - /** - * Sets whether tonemapping is enabled or not - */ - public set cameraToneMappingEnabled(value: boolean) { - this._imageProcessingConfiguration.toneMappingEnabled = value; - } - - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public get cameraExposure(): float { - return this._imageProcessingConfiguration.exposure; - } - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public set cameraExposure(value: float) { - this._imageProcessingConfiguration.exposure = value; - } - - /** - * Gets The camera contrast used on this material. - */ - public get cameraContrast(): float { - return this._imageProcessingConfiguration.contrast; - } - - /** - * Sets The camera contrast used on this material. - */ - public set cameraContrast(value: float) { - this._imageProcessingConfiguration.contrast = value; - } - - /** - * Gets the Color Grading 2D Lookup Texture. - */ - public get cameraColorGradingTexture(): Nullable { - return this._imageProcessingConfiguration.colorGradingTexture; - } - /** - * Sets the Color Grading 2D Lookup Texture. - */ - public set cameraColorGradingTexture(value: Nullable) { - (this.imageProcessingConfiguration).colorGradingTexture = value; - } - - /** - * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public get cameraColorCurves(): Nullable { - return (this.imageProcessingConfiguration).colorCurves; - } - /** - * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public set cameraColorCurves(value: Nullable) { - (this.imageProcessingConfiguration).colorCurves = value; - } - /** * Due to a bug in iOS10, video tags (which are using the background material) are in BGR and not RGB. * Setting this flag to true (not done automatically!) will convert it back to RGB. @@ -774,57 +601,14 @@ export class BackgroundMaterial extends PushMaterial { } const reflectionTexture = this._reflectionTexture; + PrepareDefinesForIBL(scene, reflectionTexture, defines); if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { if (!reflectionTexture.isReadyOrNotBlocking()) { return false; } - - defines.REFLECTION = true; - defines.GAMMAREFLECTION = reflectionTexture.gammaSpace; - defines.RGBDREFLECTION = reflectionTexture.isRGBD; - defines.REFLECTIONBLUR = this._reflectionBlur > 0; - defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha; defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV; defines.REFLECTIONBGR = this.switchToBGR; - - if (reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) { - defines.INVERTCUBICMAP = true; - } - - defines.REFLECTIONMAP_3D = reflectionTexture.isCube; - defines.REFLECTIONMAP_OPPOSITEZ = defines.REFLECTIONMAP_3D && this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ; - - switch (reflectionTexture.coordinatesMode) { - case Texture.EXPLICIT_MODE: - defines.REFLECTIONMAP_EXPLICIT = true; - break; - case Texture.PLANAR_MODE: - defines.REFLECTIONMAP_PLANAR = true; - break; - case Texture.PROJECTION_MODE: - defines.REFLECTIONMAP_PROJECTION = true; - break; - case Texture.SKYBOX_MODE: - defines.REFLECTIONMAP_SKYBOX = true; - break; - case Texture.SPHERICAL_MODE: - defines.REFLECTIONMAP_SPHERICAL = true; - break; - case Texture.EQUIRECTANGULAR_MODE: - defines.REFLECTIONMAP_EQUIRECTANGULAR = true; - break; - case Texture.FIXED_EQUIRECTANGULAR_MODE: - defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true; - break; - case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE: - defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true; - break; - case Texture.CUBIC_MODE: - case Texture.INVCUBIC_MODE: - default: - defines.REFLECTIONMAP_CUBIC = true; - break; - } + defines.REFLECTIONBLUR = this._reflectionBlur > 0; if (this.reflectionFresnel) { defines.REFLECTIONFRESNEL = true; @@ -839,25 +623,9 @@ export class BackgroundMaterial extends PushMaterial { defines.REFLECTIONFALLOFF = false; } } else { - defines.REFLECTION = false; defines.REFLECTIONFRESNEL = false; defines.REFLECTIONFALLOFF = false; defines.REFLECTIONBLUR = false; - defines.REFLECTIONMAP_3D = false; - defines.REFLECTIONMAP_SPHERICAL = false; - defines.REFLECTIONMAP_PLANAR = false; - defines.REFLECTIONMAP_CUBIC = false; - defines.REFLECTIONMAP_PROJECTION = false; - defines.REFLECTIONMAP_SKYBOX = false; - defines.REFLECTIONMAP_EXPLICIT = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; - defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; - defines.INVERTCUBICMAP = false; - defines.REFLECTIONMAP_OPPOSITEZ = false; - defines.LODINREFLECTIONALPHA = false; - defines.GAMMAREFLECTION = false; - defines.RGBDREFLECTION = false; } } @@ -956,9 +724,6 @@ export class BackgroundMaterial extends PushMaterial { "vPrimaryColor", "vPrimaryColorShadow", - "vReflectionInfos", - "reflectionMatrix", - "vReflectionMicrosurfaceInfos", "fFovMultiplier", "shadowLevel", @@ -975,7 +740,8 @@ export class BackgroundMaterial extends PushMaterial { ]; AddClipPlaneUniforms(uniforms); - const samplers = ["diffuseSampler", "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh"]; + const samplers = ["diffuseSampler"]; + PrepareUniformsAndSamplersForIBL(uniforms, samplers, false); const uniformBuffers = ["Material", "Scene"]; if (ImageProcessingConfiguration) { @@ -1085,10 +851,7 @@ export class BackgroundMaterial extends PushMaterial { this._uniformBuffer.addUniform("vPrimaryColor", 4); this._uniformBuffer.addUniform("vPrimaryColorShadow", 4); this._uniformBuffer.addUniform("vDiffuseInfos", 2); - this._uniformBuffer.addUniform("vReflectionInfos", 2); this._uniformBuffer.addUniform("diffuseMatrix", 16); - this._uniformBuffer.addUniform("reflectionMatrix", 16); - this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3); this._uniformBuffer.addUniform("fFovMultiplier", 1); this._uniformBuffer.addUniform("pointSize", 1); this._uniformBuffer.addUniform("shadowLevel", 1); @@ -1097,6 +860,8 @@ export class BackgroundMaterial extends PushMaterial { this._uniformBuffer.addUniform("vReflectionControl", 4); this._uniformBuffer.addUniform("projectedGroundInfos", 2); + PrepareUniformLayoutForIBL(this._uniformBuffer, true, false, false); + this._uniformBuffer.create(); } @@ -1164,17 +929,7 @@ export class BackgroundMaterial extends PushMaterial { BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse"); } - if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - this._uniformBuffer.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix()); - this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, this._reflectionBlur); - - this._uniformBuffer.updateFloat3( - "vReflectionMicrosurfaceInfos", - reflectionTexture.getSize().width, - reflectionTexture.lodGenerationScale, - reflectionTexture.lodGenerationOffset - ); - } + BindIBLParameters(scene, defines, this._uniformBuffer, reflectionTexture, false, true); } if (this.shadowLevel > 0) { @@ -1204,15 +959,7 @@ export class BackgroundMaterial extends PushMaterial { } if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - if (defines.REFLECTIONBLUR && defines.TEXTURELODSUPPORT) { - this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture); - } else if (!defines.REFLECTIONBLUR) { - this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture); - } else { - this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture); - this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture); - this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture); - } + BindIBLSamplers(scene, defines, this._uniformBuffer, reflectionTexture); if (defines.REFLECTIONFRESNEL) { this._uniformBuffer.updateFloat3("vBackgroundCenter", this.sceneCenter.x, this.sceneCenter.y, this.sceneCenter.z); diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index 3508fceab1e..d39371bb844 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterial.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterial.ts @@ -10,14 +10,12 @@ import { NodeMaterialBuildState } from "./nodeMaterialBuildState"; import type { IEffectCreationOptions } from "../effect"; import { Effect } from "../effect"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; -import type { Observer } from "../../Misc/observable"; import { Observable } from "../../Misc/observable"; import { NodeMaterialBlockTargets } from "./Enums/nodeMaterialBlockTargets"; import { NodeMaterialBuildStateSharedData } from "./nodeMaterialBuildStateSharedData"; import type { SubMesh } from "../../Meshes/subMesh"; import { MaterialDefines } from "../../Materials/materialDefines"; import type { NodeMaterialOptimizer } from "./Optimizers/nodeMaterialOptimizer"; -import type { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; import type { Nullable } from "../../types"; import { VertexBuffer } from "../../Buffers/buffer"; import { Tools } from "../../Misc/tools"; @@ -67,11 +65,13 @@ import type { NodeMaterialTeleportOutBlock } from "./Blocks/Teleport/teleportOut import type { NodeMaterialTeleportInBlock } from "./Blocks/Teleport/teleportInBlock"; import { Logger } from "core/Misc/logger"; import { PrepareDefinesForCamera, PrepareDefinesForPrePass } from "../materialHelper.functions"; -import type { IImageProcessingConfigurationDefines } from "../imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; import { ShaderLanguage } from "../shaderLanguage"; import { AbstractEngine } from "../../Engines/abstractEngine"; import type { LoopBlock } from "./Blocks/loopBlock"; import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering"; +import { UVDefinesMixin } from "../uv.defines"; +import { ImageProcessingMixin } from "../imageProcessing"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; @@ -91,26 +91,16 @@ export interface INodeMaterialEditorOptions { }; } +class NodeMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} + /** @internal */ -export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +export class NodeMaterialDefines extends ImageProcessingDefinesMixin(NodeMaterialDefinesBase) { /** Normal */ public NORMAL = false; /** Tangent */ public TANGENT = false; /** Vertex color */ public VERTEXCOLOR_NME = false; - /** Uv1 **/ - public UV1 = false; - /** Uv2 **/ - public UV2 = false; - /** Uv3 **/ - public UV3 = false; - /** Uv4 **/ - public UV4 = false; - /** Uv5 **/ - public UV5 = false; - /** Uv6 **/ - public UV6 = false; /** Prepass **/ public PREPASS = false; @@ -177,37 +167,6 @@ export class NodeMaterialDefines extends MaterialDefines implements IImageProces /** Using a texture to store morph target data */ public MORPHTARGETS_TEXTURE = false; - /** IMAGE PROCESSING */ - public IMAGEPROCESSING = false; - /** Vignette */ - public VIGNETTE = false; - /** Multiply blend mode for vignette */ - public VIGNETTEBLENDMODEMULTIPLY = false; - /** Opaque blend mode for vignette */ - public VIGNETTEBLENDMODEOPAQUE = false; - /** Tone mapping */ - public TONEMAPPING = 0; - /** Contrast */ - public CONTRAST = false; - /** Exposure */ - public EXPOSURE = false; - /** Color curves */ - public COLORCURVES = false; - /** Color grading */ - public COLORGRADING = false; - /** 3D color grading */ - public COLORGRADING3D = false; - /** Sampler green depth */ - public SAMPLER3DGREENDEPTH = false; - /** Sampler for BGR map */ - public SAMPLER3DBGRMAP = false; - /** Dithering */ - public DITHER = false; - /** Using post process for image processing */ - public IMAGEPROCESSINGPOSTPROCESS = false; - /** Skip color clamp */ - public SKIPFINALCOLORCLAMP = false; - /** MISC. */ public BUMPDIRECTUV = 0; /** Camera is orthographic */ @@ -272,10 +231,11 @@ export type NodeMaterialTextureBlocks = | BiPlanarBlock | PrePassTextureBlock; +class NodeMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * Class used to create a node based material built by assembling shader blocks */ -export class NodeMaterial extends PushMaterial { +export class NodeMaterial extends NodeMaterialBase { private static _BuildIdGenerator: number = 0; private _options: INodeMaterialOptions; private _vertexCompilationState: NodeMaterialBuildState; @@ -413,30 +373,6 @@ export class NodeMaterial extends PushMaterial { this._options = options; } - /** - * Default configuration related to image processing available in the standard Material. - */ - protected _imageProcessingConfiguration: ImageProcessingConfiguration; - - /** - * Gets the image processing configuration used either in this material. - */ - public get imageProcessingConfiguration(): ImageProcessingConfiguration { - return this._imageProcessingConfiguration; - } - - /** - * Sets the Default image processing configuration used either in the this material. - * - * If sets to null, the scene one is in use. - */ - public set imageProcessingConfiguration(value: ImageProcessingConfiguration) { - this._attachImageProcessingConfiguration(value); - - // Ensure the effect will be rebuilt. - this._markAllSubMeshesAsTexturesDirty(); - } - /** * Gets an array of blocks that needs to be serialized even if they are not yet connected */ @@ -510,40 +446,6 @@ export class NodeMaterial extends PushMaterial { return "NodeMaterial"; } - /** - * Keep track of the image processing observer to allow dispose and replace. - */ - private _imageProcessingObserver: Nullable>; - - /** - * Attaches a new image processing configuration to the Standard Material. - * @param configuration - */ - protected _attachImageProcessingConfiguration(configuration: Nullable): void { - if (configuration === this._imageProcessingConfiguration) { - return; - } - - // Detaches observer. - if (this._imageProcessingConfiguration && this._imageProcessingObserver) { - this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); - } - - // Pick the scene configuration if needed. - if (!configuration) { - this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration; - } else { - this._imageProcessingConfiguration = configuration; - } - - // Attaches observer. - if (this._imageProcessingConfiguration) { - this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { - this._markAllSubMeshesAsImageProcessingDirty(); - }); - } - } - /** * Get a block by its name * @param name defines the name of the block to retrieve diff --git a/packages/dev/core/src/Materials/PBR/index.ts b/packages/dev/core/src/Materials/PBR/index.ts index f97e5346890..1137c63f604 100644 --- a/packages/dev/core/src/Materials/PBR/index.ts +++ b/packages/dev/core/src/Materials/PBR/index.ts @@ -5,6 +5,7 @@ export * from "./pbrBRDFConfiguration"; export * from "./pbrClearCoatConfiguration"; export * from "./pbrIridescenceConfiguration"; export * from "./pbrMaterial"; +export * from "./openPbrMaterial"; export * from "./pbrMetallicRoughnessMaterial"; export * from "./pbrSpecularGlossinessMaterial"; export * from "./pbrSheenConfiguration"; @@ -15,3 +16,7 @@ export * from "../../ShadersWGSL/pbr.vertex"; export * from "../../ShadersWGSL/pbr.fragment"; export * from "../../Shaders/pbr.vertex"; export * from "../../Shaders/pbr.fragment"; +export * from "../../ShadersWGSL/openpbr.vertex"; +export * from "../../ShadersWGSL/openpbr.fragment"; +export * from "../../Shaders/openpbr.vertex"; +export * from "../../Shaders/openpbr.fragment"; diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts new file mode 100644 index 00000000000..d6ca912183a --- /dev/null +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -0,0 +1,2541 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { serialize, expandToProperty, serializeAsTexture, addAccessorsForMaterialProperty } from "../../Misc/decorators"; +import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; +import type { Nullable } from "../../types"; +import { Scene } from "../../scene"; +import { Color3, Color4 } from "../../Maths/math.color"; +import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; +import type { BaseTexture } from "../../Materials/Textures/baseTexture"; +import { PBRBaseMaterial } from "./pbrBaseMaterial"; +import { RegisterClass } from "../../Misc/typeStore"; +import { Material } from "../material"; +import { SerializationHelper } from "../../Misc/decorators.serialization"; + +import type { AbstractMesh } from "../../Meshes/abstractMesh"; +import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; +import { MaterialDefines } from "../materialDefines"; +import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; +import { EffectFallbacks } from "../effectFallbacks"; +import { AddClipPlaneUniforms, BindClipPlane } from "../clipPlaneMaterialHelper"; +import { + BindBonesParameters, + BindFogParameters, + BindLights, + BindLogDepth, + BindMorphTargetParameters, + BindTextureMatrix, + BindIBLParameters, + BindIBLSamplers, + HandleFallbacksForShadows, + PrepareAttributesForBakedVertexAnimation, + PrepareAttributesForBones, + PrepareAttributesForInstances, + PrepareAttributesForMorphTargets, + PrepareDefinesForAttributes, + PrepareDefinesForFrameBoundValues, + PrepareDefinesForLights, + PrepareDefinesForIBL, + PrepareDefinesForMergedUV, + PrepareDefinesForMisc, + PrepareDefinesForMultiview, + PrepareDefinesForOIT, + PrepareDefinesForPrePass, + PrepareUniformsAndSamplersList, + PrepareUniformsAndSamplersForIBL, + PrepareUniformLayoutForIBL, +} from "../materialHelper.functions"; +import { Constants } from "../../Engines/constants"; +import { VertexBuffer } from "../../Buffers/buffer"; +import { MaterialPluginEvent } from "../materialPluginEvent"; +import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering"; +import { PrePassConfiguration } from "../prePassConfiguration"; +import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../../Materials/material"; +import { ShaderLanguage } from "../shaderLanguage"; +import { MaterialFlags } from "../materialFlags"; +import type { SubMesh } from "../../Meshes/subMesh"; +import { Logger } from "core/Misc/logger"; +import { UVDefinesMixin } from "../uv.defines"; +import { Vector2, Vector3, Vector4, TmpVectors } from "core/Maths/math.vector"; +import type { Matrix } from "core/Maths/math.vector"; +import type { Mesh } from "../../Meshes/mesh"; +import { ImageProcessingMixin } from "../imageProcessing"; +import { PushMaterial } from "../pushMaterial"; +import { SmartArray } from "../../Misc/smartArray"; +import type { RenderTargetTexture } from "../Textures/renderTargetTexture"; +import type { IAnimatable } from "../../Animations/animatable.interface"; + +const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; + +class Uniform { + public name: string; + public numComponents: number; + public linkedProperties: { [name: string]: Property } = {}; + public populateVectorFromLinkedProperties(vector: Vector4 | Vector3 | Vector2): void { + const destinationSize = vector instanceof Vector4 ? 4 : vector instanceof Vector3 ? 3 : vector instanceof Vector2 ? 2 : 1; + for (const propKey in this.linkedProperties) { + const prop = this.linkedProperties[propKey]; + const sourceSize = prop.numComponents; + if (destinationSize < sourceSize || prop.targetUniformComponentOffset > destinationSize - sourceSize) { + if (sourceSize == 1) { + Logger.Error(`Float property ${prop.name} has an offset that is too large.`); + } else { + Logger.Error(`Vector${sourceSize} property ${prop.name} won't fit in Vector${destinationSize} or has an offset that is too large.`); + } + return; + } + if (typeof prop.value === "number") { + Uniform._tmpArray[prop.targetUniformComponentOffset] = prop.value; + } else { + prop.value.toArray(Uniform._tmpArray, prop.targetUniformComponentOffset); + } + } + vector.fromArray(Uniform._tmpArray); + } + public constructor(name: string, componentNum: number) { + this.name = name; + this.numComponents = componentNum; + } + private static _tmpArray: number[] = [0, 0, 0, 0]; +} + +/** + * Defines a property for the OpenPBRMaterial. + */ +class Property { + public name: string; + public targetUniformName: string; + public defaultValue: T; + public value: T; + // public includeAlphaFromProp: string = ""; + + /** + * If not given a type, there will be no uniform defined for this property and + * it will be assumed that the value will be packed into the already existing "uniformName" uniform. + */ + public targetUniformComponentNum: number = 4; // Default to vec4 + public targetUniformComponentOffset: number = 0; + + /** + * Creates a new Property instance. + * @param name The name of the property in the shader + * @param defaultValue The default value of the property + * @param targetUniformName The name of the property in the shader uniform block + * @param targetUniformComponentNum The number of components in the target uniform. All properties that are + * packed into the same uniform must agree on the size of the target uniform. + * @param targetUniformComponentOffset The offset in the uniform where this property will be packed. + */ + constructor(name: string, defaultValue: T, targetUniformName: string, targetUniformComponentNum: number, targetUniformComponentOffset: number = 0) { + this.name = name; + this.targetUniformName = targetUniformName; + this.defaultValue = defaultValue; + this.value = defaultValue; + this.targetUniformComponentNum = targetUniformComponentNum; + this.targetUniformComponentOffset = targetUniformComponentOffset; + } + + /** + * Returns the number of components of the property based on its default value type. + */ + public get numComponents(): number { + if (typeof this.defaultValue === "number") { + return 1; + } else if (this.defaultValue instanceof Color3) { + return 3; + } else if (this.defaultValue instanceof Color4) { + return 4; + } else if (this.defaultValue instanceof Vector2) { + return 2; + } else if (this.defaultValue instanceof Vector3) { + return 3; + } else if (this.defaultValue instanceof Vector4) { + return 4; + } + return 0; // Default size for unsupported types + } +} + +class Sampler { + public name: string; + public value: Nullable = null; // Texture value, default to null + public samplerPrefix: string = ""; // The name of the sampler in the shader + public textureDefine: string = ""; // The define used in the shader for this sampler + + /** + * The name of the sampler used in the shader. + * If this naming changes, we'll also need to change: + * - samplerFragmentDeclaration.fx + * - openpbr.fragment.fx + */ + public get samplerName(): string { + return this.samplerPrefix + "Sampler"; + } + /** + * The name of the sampler info used in the shader. + * If this naming changes, we'll also need to change: + * - openpbr.vertex.fx + * - openpbr.fragment.fx + */ + public get samplerInfoName(): string { + return "v" + this.samplerPrefix.charAt(0).toUpperCase() + this.samplerPrefix.slice(1) + "Infos"; + } + /** + * The name of the matrix used for this sampler in the shader. + * If this naming changes, we'll also need to change: + * - materialHelper.functions.BindTextureMatrix + * - samplerVertexImplementation.fx + * - openpbr.fragment.fx + */ + public get samplerMatrixName(): string { + return this.samplerPrefix + "Matrix"; + } + /** + * Creates a new Sampler instance. + * @param name The name of the texture property + * @param samplerPrefix The prefix used for the name of the sampler in the shader + * @param textureDefine The define used in the shader for this sampler + */ + constructor(name: string, samplerPrefix: string, textureDefine: string) { + this.name = name; + this.samplerPrefix = samplerPrefix; + this.textureDefine = textureDefine; + } +} + +class OpenPBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} +/** + * Manages the defines for the PBR Material. + * @internal + */ +export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRMaterialDefinesBase) { + public PBR = true; + + public NUM_SAMPLES = "0"; + public REALTIME_FILTERING = false; + public IBL_CDF_FILTERING = false; + + public VERTEXCOLOR = false; + + public BAKED_VERTEX_ANIMATION_TEXTURE = false; + + public VERTEXALPHA = false; + public ALPHATEST = false; + public DEPTHPREPASS = false; + public ALPHABLEND = false; + public ALPHAFROMALBEDO = false; + public ALPHATESTVALUE = "0.5"; + public PREMULTIPLYALPHA = false; + + public REFLECTIVITY_GAMMA = false; + public REFLECTIVITYDIRECTUV = 0; + public SPECULARTERM = false; + + public MICROSURFACEFROMREFLECTIVITYMAP = false; + public MICROSURFACEAUTOMATIC = false; + public LODBASEDMICROSFURACE = false; + + public METALLICWORKFLOW = true; + public ROUGHNESSSTOREINMETALMAPALPHA = false; + public ROUGHNESSSTOREINMETALMAPGREEN = false; + public METALLNESSSTOREINMETALMAPBLUE = false; + public AOSTOREINMETALMAPRED = false; + public SPECULAR_WEIGHT_USE_ALPHA_ONLY = false; + + public ENVIRONMENTBRDF = false; + public ENVIRONMENTBRDF_RGBD = false; + + public NORMAL = false; + public TANGENT = false; + public BUMP = false; + public BUMPDIRECTUV = 0; + public OBJECTSPACE_NORMALMAP = false; + public PARALLAX = false; + public PARALLAX_RHS = false; + public PARALLAXOCCLUSION = false; + public NORMALXYSCALE = true; + + public LIGHTMAP = false; + public LIGHTMAPDIRECTUV = 0; + public USELIGHTMAPASSHADOWMAP = false; + public GAMMALIGHTMAP = false; + public RGBDLIGHTMAP = false; + + public REFLECTION = false; + public REFLECTIONMAP_3D = false; + public REFLECTIONMAP_SPHERICAL = false; + public REFLECTIONMAP_PLANAR = false; + public REFLECTIONMAP_CUBIC = false; + public USE_LOCAL_REFLECTIONMAP_CUBIC = false; + public REFLECTIONMAP_PROJECTION = false; + public REFLECTIONMAP_SKYBOX = false; + public REFLECTIONMAP_EXPLICIT = false; + public REFLECTIONMAP_EQUIRECTANGULAR = false; + public REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; + public REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; + public INVERTCUBICMAP = false; + public USESPHERICALFROMREFLECTIONMAP = false; + public USEIRRADIANCEMAP = false; + public USE_IRRADIANCE_DOMINANT_DIRECTION = false; + public USESPHERICALINVERTEX = false; + public REFLECTIONMAP_OPPOSITEZ = false; + public LODINREFLECTIONALPHA = false; + public GAMMAREFLECTION = false; + public RGBDREFLECTION = false; + public LINEARSPECULARREFLECTION = false; + public RADIANCEOCCLUSION = false; + public HORIZONOCCLUSION = false; + + public INSTANCES = false; + public THIN_INSTANCES = false; + public INSTANCESCOLOR = false; + + public PREPASS = false; + public PREPASS_COLOR = false; + public PREPASS_COLOR_INDEX = -1; + public PREPASS_IRRADIANCE = false; + public PREPASS_IRRADIANCE_INDEX = -1; + public PREPASS_ALBEDO = false; + public PREPASS_ALBEDO_INDEX = -1; + public PREPASS_ALBEDO_SQRT = false; + public PREPASS_ALBEDO_SQRT_INDEX = -1; + public PREPASS_DEPTH = false; + public PREPASS_DEPTH_INDEX = -1; + public PREPASS_SCREENSPACE_DEPTH = false; + public PREPASS_SCREENSPACE_DEPTH_INDEX = -1; + public PREPASS_NORMALIZED_VIEW_DEPTH = false; + public PREPASS_NORMALIZED_VIEW_DEPTH_INDEX = -1; + public PREPASS_NORMAL = false; + public PREPASS_NORMAL_INDEX = -1; + public PREPASS_NORMAL_WORLDSPACE = false; + public PREPASS_WORLD_NORMAL = false; + public PREPASS_WORLD_NORMAL_INDEX = -1; + public PREPASS_POSITION = false; + public PREPASS_POSITION_INDEX = -1; + public PREPASS_LOCAL_POSITION = false; + public PREPASS_LOCAL_POSITION_INDEX = -1; + public PREPASS_VELOCITY = false; + public PREPASS_VELOCITY_INDEX = -1; + public PREPASS_VELOCITY_LINEAR = false; + public PREPASS_VELOCITY_LINEAR_INDEX = -1; + public PREPASS_REFLECTIVITY = false; + public PREPASS_REFLECTIVITY_INDEX = -1; + public SCENE_MRT_COUNT = 0; + + public NUM_BONE_INFLUENCERS = 0; + public BonesPerMesh = 0; + public BONETEXTURE = false; + public BONES_VELOCITY_ENABLED = false; + + public NONUNIFORMSCALING = false; + + public MORPHTARGETS = false; + public MORPHTARGETS_POSITION = false; + public MORPHTARGETS_NORMAL = false; + public MORPHTARGETS_TANGENT = false; + public MORPHTARGETS_UV = false; + public MORPHTARGETS_UV2 = false; + public MORPHTARGETS_COLOR = false; + public MORPHTARGETTEXTURE_HASPOSITIONS = false; + public MORPHTARGETTEXTURE_HASNORMALS = false; + public MORPHTARGETTEXTURE_HASTANGENTS = false; + public MORPHTARGETTEXTURE_HASUVS = false; + public MORPHTARGETTEXTURE_HASUV2S = false; + public MORPHTARGETTEXTURE_HASCOLORS = false; + public NUM_MORPH_INFLUENCERS = 0; + public MORPHTARGETS_TEXTURE = false; + + public USEPHYSICALLIGHTFALLOFF = false; + public USEGLTFLIGHTFALLOFF = false; + public TWOSIDEDLIGHTING = false; + public MIRRORED = false; + public SHADOWFLOAT = false; + public CLIPPLANE = false; + public CLIPPLANE2 = false; + public CLIPPLANE3 = false; + public CLIPPLANE4 = false; + public CLIPPLANE5 = false; + public CLIPPLANE6 = false; + public POINTSIZE = false; + public FOG = false; + public LOGARITHMICDEPTH = false; + public CAMERA_ORTHOGRAPHIC = false; + public CAMERA_PERSPECTIVE = false; + public AREALIGHTSUPPORTED = true; + + public FORCENORMALFORWARD = false; + + public SPECULARAA = false; + + public UNLIT = false; + + public DECAL_AFTER_DETAIL = false; + + public DEBUGMODE = 0; + + // BRDF defines + BRDF_V_HEIGHT_CORRELATED = true; + MS_BRDF_ENERGY_CONSERVATION = true; + SPHERICAL_HARMONICS = true; + SPECULAR_GLOSSINESS_ENERGY_CONSERVATION = true; + MIX_IBL_RADIANCE_WITH_IRRADIANCE = true; + LEGACY_SPECULAR_ENERGY_CONSERVATION = false; + BASE_DIFFUSE_MODEL = Constants.MATERIAL_DIFFUSE_MODEL_E_OREN_NAYAR; + DIELECTRIC_SPECULAR_MODEL = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR; + CONDUCTOR_SPECULAR_MODEL = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR; + + /** + * Initializes the PBR Material defines. + * @param externalProperties The external properties + */ + constructor(externalProperties?: { [name: string]: { type: string; default: any } }) { + super(externalProperties); + this.rebuild(); + } + + /** + * Resets the PBR Material defines. + */ + public override reset(): void { + super.reset(); + this.ALPHATESTVALUE = "0.5"; + this.PBR = true; + this.NORMALXYSCALE = true; + } +} + +class OpenPBRMaterialBase extends ImageProcessingMixin(PushMaterial) {} +/** + * The Physically based material of BJS. + * + * This offers the main features of a standard PBR material. + * For more information, please refer to the documentation : + * https://doc.babylonjs.com/features/featuresDeepDive/materials/using/introToPBR + */ +export class OpenPBRMaterial extends OpenPBRMaterialBase { + /** + * OpenPBRMaterialTransparencyMode: No transparency mode, Alpha channel is not use. + */ + public static readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; + + /** + * OpenPBRMaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. + */ + public static readonly PBRMATERIAL_ALPHATEST = PBRBaseMaterial.PBRMATERIAL_ALPHATEST; + + /** + * OpenPBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + */ + public static readonly PBRMATERIAL_ALPHABLEND = PBRBaseMaterial.PBRMATERIAL_ALPHABLEND; + + /** + * OpenPBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + * They are also discarded below the alpha cutoff threshold to improve performances. + */ + public static readonly PBRMATERIAL_ALPHATESTANDBLEND = PBRBaseMaterial.PBRMATERIAL_ALPHATESTANDBLEND; + + /** + * Defines the default value of how much AO map is occluding the analytical lights + * (point spot...). + */ + public static DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + + /** + * Base Weight is a multiplier on the diffuse and metal lobes. + * See OpenPBR's specs for base_weight + */ + public baseWeight: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseWeight") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseWeight: Property = new Property("base_weight", 1, "baseWeight", 1); + + /** + * Base Weight is a multiplier on the diffuse and metal lobes. + * See OpenPBR's specs for base_weight + */ + public baseWeightTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseColorTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseWeightTexture: Sampler = new Sampler("base_weight", "baseWeight", "BASE_WEIGHT"); + + /** + * Color of the base diffuse lobe. + * See OpenPBR's specs for base_color + */ + public baseColor: Color3; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseColor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseColor: Property = new Property("base_color", Color3.White(), "vBaseColor", 4); + + /** + * Base Color Texture property. + * See OpenPBR's specs for base_color + */ + public baseColorTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseColorTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseColorTexture: Sampler = new Sampler("base_color", "baseColor", "BASE_COLOR"); + + /** + * Roughness of the diffuse lobe. + * See OpenPBR's specs for base_diffuse_roughness + */ + public baseDiffuseRoughness: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseDiffuseRoughness") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseDiffuseRoughness: Property = new Property("base_diffuse_roughness", 0, "vBaseDiffuseRoughness", 1); + + /** + * Roughness of the diffuse lobe. + * See OpenPBR's specs for base_diffuse_roughness + */ + public baseDiffuseRoughnessTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseDiffuseRoughnessTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseDiffuseRoughnessTexture: Sampler = new Sampler("base_diffuse_roughness", "baseDiffuseRoughness", "BASE_DIFFUSE_ROUGHNESS"); + + /** + * Metalness of the base lobe. + * See OpenPBR's specs for base_metalness + */ + public baseMetalness: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseMetalness") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseMetalness: Property = new Property("base_metalness", 0, "vReflectanceInfo", 4, 0); + + /** + * Weight of the specular lobe. + * See OpenPBR's specs for specular_weight + */ + public specularWeight: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularWeight") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularWeight: Property = new Property("specular_weight", 1, "vReflectanceInfo", 4, 3); + + /** + * Roughness of the diffuse lobe. + * See OpenPBR's specs for base_diffuse_roughness + */ + public specularWeightTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularWeightTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularWeightTexture: Sampler = new Sampler("specular_weight", "specularWeight", "SPECULAR_WEIGHT"); + + /** + * Color of the specular lobe. + * See OpenPBR's specs for specular_color + */ + public specularColor: Color3; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularColor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularColor: Property = new Property("specular_color", Color3.White(), "vSpecularColor", 4); + + /** + * Specular Color Texture property. + * See OpenPBR's specs for specular_color + */ + public specularColorTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularColorTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularColorTexture: Sampler = new Sampler("specular_color", "specularColor", "SPECULAR_COLOR"); + + /** + * Roughness of the specular lobe. + * See OpenPBR's specs for specular_roughness + */ + public specularRoughness: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularRoughness") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularRoughness: Property = new Property("specular_roughness", 0, "vReflectanceInfo", 4, 1); + + /** + * IOR of the specular lobe. + * See OpenPBR's specs for specular_roughness + */ + public specularIor: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "specularIor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _specularIor: Property = new Property("specular_ior", 1.5, "vReflectanceInfo", 4, 2); + + /** + * Metalness and Roughness texture. + * See OpenPBR's specs for base_metalness and specular_roughness + */ + public baseMetalRoughTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseMetalRoughTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseMetalRoughTexture: Sampler = new Sampler("base_metalness_specular_roughness", "baseMetalRough", "METALLIC_ROUGHNESS"); + + /** + * Defines the opacity of the material's geometry. + * See OpenPBR's specs for geometry_opacity + */ + public geometryOpacity: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "geometryOpacity") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _geometryOpacity: Property = new Property("geometry_opacity", 1.0, "vBaseColor", 4, 3); + + /** + * Defines the opacity of the material's geometry. + * See OpenPBR's specs for geometry_opacity + */ + public geometryOpacityTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "geometryOpacityTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _geometryOpacityTexture: Sampler = new Sampler("geometry_opacity", "geometryOpacity", "GEOMETRY_OPACITY"); + + /** + * Defines the color of the material's emission. + * See OpenPBR's specs for emission_color + */ + public emissionColor: Color3; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "emissionColor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _emissionColor: Property = new Property("emission_color", Color3.Black(), "vEmissionColor", 3); + + /** + * Defines the color of the material's emission. + * See OpenPBR's specs for emission_color + */ + public emissionTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "emissionTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _emissionTexture: Sampler = new Sampler("emission", "emission", "EMISSION"); + + /** + * Defines the ambient occlusion texture. + */ + public ambientOcclusionTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "ambientOcclusionTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _ambientOcclusionTexture: Sampler = new Sampler("ambient_occlusion", "ambientOcclusion", "AMBIENT_OCCLUSION"); + + private _propertyList: { [name: string]: Property }; + private _uniformsList: { [name: string]: Uniform } = {}; + private _samplersList: { [name: string]: Sampler } = {}; + private _samplerDefines: { [name: string]: { type: string; default: any } } = {}; + + /** + * Intensity of the direct lights e.g. the four lights available in your scene. + * This impacts both the direct diffuse and specular highlights. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public directIntensity: number = 1.0; + + /** + * Intensity of the emissive part of the material. + * This helps controlling the emissive effect without modifying the emissive color. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public emissiveIntensity: number = 1.0; + + /** + * Intensity of the environment e.g. how much the environment will light the object + * either through harmonics for rough material or through the reflection for shiny ones. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public environmentIntensity: number = 1.0; + + /** + * Debug Control allowing disabling the bump map on this material. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public disableBumpMap: boolean = false; + + /** + * Stores the reflection values in a texture. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectionTexture: Nullable; + + /** + * Specifies that the specular weight is stored in the alpha channel of the specular weight texture. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useSpecularWeightFromTextureAlpha = false; + + /** + * Stores surface normal data used to displace a mesh in a texture. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public bumpTexture: Nullable; + + /** + * Stores the pre-calculated light information of a mesh in a texture. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty", null) + public lightmapTexture: Nullable; + + /** + * If true, the light map contains occlusion information instead of lighting info. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useLightmapAsShadowmap = false; + + /** + * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") + public useAlphaFromAlbedoTexture = false; + + /** + * Enforces alpha test in opaque or blend mode in order to improve the performances of some situations. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") + public forceAlphaTest = false; + + /** + * Defines the alpha limits in alpha test mode. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") + public alphaCutOff = 0.4; + + /** + * Specifies if the reflectivity texture contains the glossiness information in its alpha channel. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useMicroSurfaceFromReflectivityMapAlpha = false; + + /** + * Specifies if the metallic texture contains the ambient occlusion information in its red channel. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useAmbientOcclusionFromMetallicTextureRed = false; + + /** + * Specifies if the ambient texture contains the ambient occlusion information in its red channel only. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useAmbientInGrayScale = false; + + /** + * In case the reflectivity map does not contain the microsurface information in its alpha channel, + * The material will try to infer what glossiness each pixel should be. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useAutoMicroSurfaceFromReflectivityMap = false; + + /** + * BJS is using an hardcoded light falloff based on a manually sets up range. + * In PBR, one way to represents the falloff is to use the inverse squared root algorithm. + * This parameter can help you switch back to the BJS mode in order to create scenes using both materials. + */ + @serialize() + public get usePhysicalLightFalloff(): boolean { + return this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL; + } + + /** + * BJS is using an hardcoded light falloff based on a manually sets up range. + * In PBR, one way to represents the falloff is to use the inverse squared root algorithm. + * This parameter can help you switch back to the BJS mode in order to create scenes using both materials. + */ + public set usePhysicalLightFalloff(value: boolean) { + if (value !== this.usePhysicalLightFalloff) { + // Ensure the effect will be rebuilt. + this._markAllSubMeshesAsTexturesDirty(); + + if (value) { + this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL; + } else { + this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_STANDARD; + } + } + } + + /** + * In order to support the falloff compatibility with gltf, a special mode has been added + * to reproduce the gltf light falloff. + */ + @serialize() + public get useGLTFLightFalloff(): boolean { + return this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_GLTF; + } + + /** + * In order to support the falloff compatibility with gltf, a special mode has been added + * to reproduce the gltf light falloff. + */ + public set useGLTFLightFalloff(value: boolean) { + if (value !== this.useGLTFLightFalloff) { + // Ensure the effect will be rebuilt. + this._markAllSubMeshesAsTexturesDirty(); + + if (value) { + this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_GLTF; + } else { + this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_STANDARD; + } + } + } + + /** + * Allows using an object space normal map (instead of tangent space). + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useObjectSpaceNormalMap = false; + + /** + * Allows using the bump map in parallax mode. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useParallax = false; + + /** + * Allows using the bump map in parallax occlusion mode. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useParallaxOcclusion = false; + + /** + * Controls the scale bias of the parallax mode. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public parallaxScaleBias = 0.05; + + /** + * If sets to true, disables all the lights affecting the material. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsLightsDirty") + public disableLighting = false; + + /** + * Force the shader to compute irradiance in the fragment shader in order to take bump in account. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public forceIrradianceInFragment = false; + + /** + * Number of Simultaneous lights allowed on the material. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsLightsDirty") + public maxSimultaneousLights = 4; + + /** + * If sets to true, x component of normal map value will invert (x = 1.0 - x). + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public invertNormalMapX = false; + + /** + * If sets to true, y component of normal map value will invert (y = 1.0 - y). + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public invertNormalMapY = false; + + /** + * If sets to true and backfaceCulling is false, normals will be flipped on the backside. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public twoSidedLighting = false; + + /** + * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested. + * And/Or occlude the blended part. (alpha is converted to gamma to compute the fresnel) + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useAlphaFresnel = false; + + /** + * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested. + * And/Or occlude the blended part. (alpha stays linear to compute the fresnel) + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useLinearAlphaFresnel = false; + + /** + * Let user defines the brdf lookup texture used for IBL. + * A default 8bit version is embedded but you could point at : + * * Default texture: https://assets.babylonjs.com/environments/correlatedMSBRDF_RGBD.png + * * Default 16bit pixel depth texture: https://assets.babylonjs.com/environments/correlatedMSBRDF.dds + * * LEGACY Default None correlated https://assets.babylonjs.com/environments/uncorrelatedBRDF_RGBD.png + * * LEGACY Default None correlated 16bit pixel depth https://assets.babylonjs.com/environments/uncorrelatedBRDF.dds + */ + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public environmentBRDFTexture: Nullable = null; + + /** + * Force normal to face away from face. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public forceNormalForward = false; + + /** + * Enables specular anti aliasing in the PBR shader. + * It will both interacts on the Geometry for analytical and IBL lighting. + * It also prefilter the roughness map based on the bump values. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public enableSpecularAntiAliasing = false; + + /** + * This parameters will enable/disable Horizon occlusion to prevent normal maps to look shiny when the normal + * makes the reflect vector face the model (under horizon). + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useHorizonOcclusion = true; + + /** + * This parameters will enable/disable radiance occlusion by preventing the radiance to lit + * too much the area relying on ambient texture to define their ambient occlusion. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useRadianceOcclusion = true; + + /** + * If set to true, no lighting calculations will be applied. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsMiscDirty") + public unlit = false; + + /** + * If sets to true, the decal map will be applied after the detail map. Else, it is applied before (default: false) + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsMiscDirty") + public applyDecalMapAfterDetailMap = false; + + /** + * PBRMaterialLightFalloff Physical: light is falling off following the inverse squared distance law. + */ + public static readonly LIGHTFALLOFF_PHYSICAL = 0; + + /** + * PBRMaterialLightFalloff gltf: light is falling off as described in the gltf moving to PBR document + * to enhance interoperability with other engines. + */ + public static readonly LIGHTFALLOFF_GLTF = 1; + + /** + * PBRMaterialLightFalloff Standard: light is falling off like in the standard material + * to enhance interoperability with other materials. + */ + public static readonly LIGHTFALLOFF_STANDARD = 2; + + /** + * Force all the PBR materials to compile to glsl even on WebGPU engines. + * False by default. This is mostly meant for backward compatibility. + */ + public static ForceGLSL = false; + + /** + * Intensity of the direct lights e.g. the four lights available in your scene. + * This impacts both the direct diffuse and specular highlights. + * @internal + */ + public _directIntensity: number = 1.0; + + /** + * Intensity of the emissive part of the material. + * This helps controlling the emissive effect without modifying the emissive color. + * @internal + */ + public _emissiveIntensity: number = 1.0; + + /** + * Intensity of the environment e.g. how much the environment will light the object + * either through harmonics for rough material or through the reflection for shiny ones. + * @internal + */ + public _environmentIntensity: number = 1.0; + + /** + * This stores the direct, emissive, environment, and specular light intensities into a Vector4. + */ + private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, 1.0); + + /** + * Debug Control allowing disabling the bump map on this material. + * @internal + */ + public _disableBumpMap: boolean = false; + + /** + * Stores the reflection values in a texture. + * @internal + */ + public _reflectionTexture: Nullable = null; + + /** + * Specifies that only the A channel from _metallicReflectanceTexture should be used. + * If false, both RGB and A channels will be used + * @internal + */ + public _useSpecularWeightFromTextureAlpha = false; + + /** + * Stores surface normal data used to displace a mesh in a texture. + * @internal + */ + public _bumpTexture: Nullable = null; + + /** + * Stores the pre-calculated light information of a mesh in a texture. + * @internal + */ + public _lightmapTexture: Nullable = null; + + /** + * The color of a material in ambient lighting. + * @internal + */ + public _ambientColor = new Color3(0, 0, 0); + + /** + * AKA Specular Color in other nomenclature. + * @internal + */ + public _reflectivityColor = new Color3(1, 1, 1); + + /** + * The color applied when light is reflected from a material. + * @internal + */ + public _reflectionColor = new Color3(1, 1, 1); + + /** + * Specifies that the material will use the light map as a show map. + * @internal + */ + public _useLightmapAsShadowmap = false; + + /** + * This parameters will enable/disable Horizon occlusion to prevent normal maps to look shiny when the normal + * makes the reflect vector face the model (under horizon). + * @internal + */ + public _useHorizonOcclusion = true; + + /** + * This parameters will enable/disable radiance occlusion by preventing the radiance to lit + * too much the area relying on ambient texture to define their ambient occlusion. + * @internal + */ + public _useRadianceOcclusion = true; + + /** + * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending. + * @internal + */ + public _useAlphaFromAlbedoTexture = false; + + /** + * Specifies that the material will keeps the specular highlights over a transparent surface (only the most luminous ones). + * A car glass is a good example of that. When sun reflects on it you can not see what is behind. + * @internal + */ + public _useSpecularOverAlpha = true; + + /** + * Specifies if the reflectivity texture contains the glossiness information in its alpha channel. + * @internal + */ + public _useMicroSurfaceFromReflectivityMapAlpha = false; + + /** + * Specifies if the metallic texture contains the ambient occlusion information in its red channel. + * @internal + */ + public _useAmbientOcclusionFromMetallicTextureRed = false; + + /** + * Specifies if the ambient texture contains the ambient occlusion information in its red channel only. + * @internal + */ + public _useAmbientInGrayScale = false; + + /** + * In case the reflectivity map does not contain the microsurface information in its alpha channel, + * The material will try to infer what glossiness each pixel should be. + * @internal + */ + public _useAutoMicroSurfaceFromReflectivityMap = false; + + /** + * Defines the falloff type used in this material. + * It by default is Physical. + * @internal + */ + public _lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL; + + /** + * Specifies that the material will keeps the reflection highlights over a transparent surface (only the most luminous ones). + * A car glass is a good example of that. When the street lights reflects on it you can not see what is behind. + * @internal + */ + public _useRadianceOverAlpha = true; + + /** + * Allows using an object space normal map (instead of tangent space). + * @internal + */ + public _useObjectSpaceNormalMap = false; + + /** + * Allows using the bump map in parallax mode. + * @internal + */ + public _useParallax = false; + + /** + * Allows using the bump map in parallax occlusion mode. + * @internal + */ + public _useParallaxOcclusion = false; + + /** + * Controls the scale bias of the parallax mode. + * @internal + */ + public _parallaxScaleBias = 0.05; + + /** + * If sets to true, disables all the lights affecting the material. + * @internal + */ + public _disableLighting = false; + + /** + * Number of Simultaneous lights allowed on the material. + * @internal + */ + public _maxSimultaneousLights = 4; + + /** + * If sets to true, x component of normal map value will be inverted (x = 1.0 - x). + * @internal + */ + public _invertNormalMapX = false; + + /** + * If sets to true, y component of normal map value will be inverted (y = 1.0 - y). + * @internal + */ + public _invertNormalMapY = false; + + /** + * If sets to true and backfaceCulling is false, normals will be flipped on the backside. + * @internal + */ + public _twoSidedLighting = false; + + /** + * Defines the alpha limits in alpha test mode. + * @internal + */ + public _alphaCutOff = 0.4; + + /** + * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested. + * And/Or occlude the blended part. (alpha is converted to gamma to compute the fresnel) + * @internal + */ + public _useAlphaFresnel = false; + + /** + * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested. + * And/Or occlude the blended part. (alpha stays linear to compute the fresnel) + * @internal + */ + public _useLinearAlphaFresnel = false; + + /** + * Specifies the environment BRDF texture used to compute the scale and offset roughness values + * from cos theta and roughness: + * http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + * @internal + */ + public _environmentBRDFTexture: Nullable = null; + + /** + * Force the shader to compute irradiance in the fragment shader in order to take bump in account. + * @internal + */ + public _forceIrradianceInFragment = false; + + private _realTimeFiltering: boolean = false; + /** + * Enables realtime filtering on the texture. + */ + public get realTimeFiltering() { + return this._realTimeFiltering; + } + public set realTimeFiltering(b: boolean) { + this._realTimeFiltering = b; + this.markAsDirty(Constants.MATERIAL_TextureDirtyFlag); + } + + private _realTimeFilteringQuality: number = Constants.TEXTURE_FILTERING_QUALITY_LOW; + /** + * Quality switch for realtime filtering + */ + public get realTimeFilteringQuality(): number { + return this._realTimeFilteringQuality; + } + public set realTimeFilteringQuality(n: number) { + this._realTimeFilteringQuality = n; + this.markAsDirty(Constants.MATERIAL_TextureDirtyFlag); + } + + /** + * Can this material render to several textures at once + */ + public override get canRenderToMRT() { + return true; + } + + /** + * Force normal to face away from face. + * @internal + */ + public _forceNormalForward = false; + + /** + * Enables specular anti aliasing in the PBR shader. + * It will both interacts on the Geometry for analytical and IBL lighting. + * It also prefilter the roughness map based on the bump values. + * @internal + */ + public _enableSpecularAntiAliasing = false; + + /** + * Stores the available render targets. + */ + private _renderTargets = new SmartArray(16); + + /** + * If set to true, no lighting calculations will be applied. + */ + private _unlit = false; + + /** + * If sets to true, the decal map will be applied after the detail map. Else, it is applied before (default: false) + */ + private _applyDecalMapAfterDetailMap = false; + + private _debugMode = 0; + + private _shadersLoaded = false; + private _breakShaderLoadedCheck = false; + + /** + * @internal + * This is reserved for the inspector. + * Defines the material debug mode. + * It helps seeing only some components of the material while troubleshooting. + */ + @expandToProperty("_markAllSubMeshesAsMiscDirty") + public debugMode = 0; + + /** + * @internal + * This is reserved for the inspector. + * Specify from where on screen the debug mode should start. + * The value goes from -1 (full screen) to 1 (not visible) + * It helps with side by side comparison against the final render + * This defaults to -1 + */ + public debugLimit = -1; + + /** + * @internal + * This is reserved for the inspector. + * As the default viewing range might not be enough (if the ambient is really small for instance) + * You can use the factor to better multiply the final value. + */ + public debugFactor = 1; + + /** + * Defines additional PrePass parameters for the material. + */ + public readonly prePassConfiguration: PrePassConfiguration; + + protected _cacheHasRenderTargetTextures = false; + + /** + * Instantiates a new OpenPBRMaterial instance. + * + * @param name The material name + * @param scene The scene the material will be use in. + * @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false + */ + constructor(name: string, scene?: Scene, forceGLSL = false) { + super(name, scene, undefined, forceGLSL || PBRBaseMaterial.ForceGLSL); + + // Setup the default processing configuration to the scene. + this._attachImageProcessingConfiguration(null); + + this.getRenderTargetTextures = (): SmartArray => { + this._renderTargets.reset(); + + if (MaterialFlags.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { + this._renderTargets.push(this._reflectionTexture); + } + + this._eventInfo.renderTargets = this._renderTargets; + this._callbackPluginEventFillRenderTargetTextures(this._eventInfo); + + return this._renderTargets; + }; + + this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene()); + this.prePassConfiguration = new PrePassConfiguration(); + this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene()); + + // Build the internal property list that can be used to generate and update the uniform buffer + this._propertyList = {}; + for (const key of Object.getOwnPropertyNames(this)) { + const value = (this as any)[key]; + if (value instanceof Property) { + this._propertyList[key] = value; + } + } + // Build the internal uniforms list that is used for combining and updating + // property values in the uniform buffer + const propertyKeys = Object.keys(this._propertyList); + propertyKeys.forEach((key) => { + const prop = this._propertyList[key]; + let uniform = this._uniformsList[prop.targetUniformName]; + if (!uniform) { + uniform = new Uniform(prop.targetUniformName, prop.targetUniformComponentNum); + this._uniformsList[prop.targetUniformName] = uniform; + } else if (uniform.numComponents !== prop.targetUniformComponentNum) { + Logger.Error(`Uniform ${prop.targetUniformName} already exists of size ${uniform.numComponents}, but trying to set it to ${prop.targetUniformComponentNum}.`); + } + uniform.linkedProperties[prop.name] = prop; + }); + + // Build the internal list of samplers + this._samplersList = {}; + for (const key of Object.getOwnPropertyNames(this)) { + const value = (this as any)[key]; + if (value instanceof Sampler) { + this._samplersList[key] = value; + } + } + + // For each sampler in _samplersList, add defines to be added to OpenPBRMaterialDefines + for (const samplerKey in this._samplersList) { + const sampler = this._samplersList[samplerKey]; + const defineName = sampler.textureDefine; + this._samplerDefines[defineName] = { type: "boolean", default: false }; + this._samplerDefines[defineName + "DIRECTUV"] = { type: "number", default: 0 }; + this._samplerDefines[defineName + "_GAMMA"] = { type: "boolean", default: false }; + } + + // Arg. Why do I have to add these references to get rid of the linting errors? + this._baseWeight; + this._baseWeightTexture; + this._baseColor; + this._baseColorTexture; + this._baseDiffuseRoughness; + this._baseDiffuseRoughnessTexture; + this._baseMetalness; + this._specularWeight; + this._specularWeightTexture; + this._specularColor; + this._specularColorTexture; + this._specularRoughness; + this._specularIor; + this._baseMetalRoughTexture; + this._geometryOpacity; + this._geometryOpacityTexture; + this._emissionColor; + this._emissionTexture; + this._ambientOcclusionTexture; + } + + /** + * Gets a boolean indicating that current material needs to register RTT + */ + public override get hasRenderTargetTextures(): boolean { + if (MaterialFlags.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { + return true; + } + + return this._cacheHasRenderTargetTextures; + } + + /** + * Can this material render to prepass + */ + public override get isPrePassCapable(): boolean { + return !this.disableDepthWrite; + } + + /** + * @returns the name of the material class. + */ + public override getClassName(): string { + return "OpenPBRMaterial"; + } + + /** + * Returns true if alpha blending should be disabled. + */ + protected override get _disableAlphaBlending(): boolean { + return this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_OPAQUE || this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST; + } + + /** + * @returns whether or not this material should be rendered in alpha blend mode. + */ + public override needAlphaBlending(): boolean { + if (this._hasTransparencyMode) { + return this._transparencyModeIsBlend; + } + + if (this._disableAlphaBlending) { + return false; + } + + return this.geometryOpacity < 1.0 || this.geometryOpacityTexture != null || this._shouldUseAlphaFromAlbedoTexture(); + } + + /** + * @returns whether or not this material should be rendered in alpha test mode. + */ + public override needAlphaTesting(): boolean { + if (this._hasTransparencyMode) { + return this._transparencyModeIsTest; + } + + return this._hasAlphaChannel() && (this._transparencyMode == null || this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST); + } + + /** + * @returns whether or not the alpha value of the albedo texture should be used for alpha blending. + */ + protected _shouldUseAlphaFromAlbedoTexture(): boolean { + return this.baseColorTexture != null && this.baseColorTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE; + } + + /** + * @returns whether or not there is a usable alpha channel for transparency. + */ + protected _hasAlphaChannel(): boolean { + return this.geometryOpacityTexture != null; + } + + /** + * Makes a duplicate of the current material. + * @param name - name to use for the new material. + * @param cloneTexturesOnlyOnce - if a texture is used in more than one channel (e.g baseColor and opacity), only clone it once and reuse it on the other channels. Default false. + * @param rootUrl defines the root URL to use to load textures + * @returns cloned material instance + */ + public override clone(name: string, cloneTexturesOnlyOnce: boolean = true, rootUrl = ""): OpenPBRMaterial { + const clone = SerializationHelper.Clone(() => new OpenPBRMaterial(name, this.getScene()), this, { cloneTexturesOnlyOnce }); + + clone.id = name; + clone.name = name; + + this.stencil.copyTo(clone.stencil); + + this._clonePlugins(clone, rootUrl); + + return clone; + } + + /** + * Serializes this PBR Material. + * @returns - An object with the serialized material. + */ + public override serialize(): any { + const serializationObject = super.serialize(); + serializationObject.customType = "BABYLON.OpenPBRMaterial"; + + return serializationObject; + } + + // Statics + /** + * Parses a PBR Material from a serialized object. + * @param source - Serialized object. + * @param scene - BJS scene instance. + * @param rootUrl - url for the scene object + * @returns - OpenPBRMaterial + */ + public static override Parse(source: any, scene: Scene, rootUrl: string): OpenPBRMaterial { + const material = SerializationHelper.Parse(() => new OpenPBRMaterial(source.name, scene), source, scene, rootUrl); + + if (source.stencil) { + material.stencil.parse(source.stencil, scene, rootUrl); + } + + Material._ParsePlugins(source, material, scene, rootUrl); + + return material; + } + + /** + * Force shader compilation + * @param mesh - Define the mesh we want to force the compilation for + * @param onCompiled - Define a callback triggered when the compilation completes + * @param options - Define the options used to create the compilation + */ + public override forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial): void { + const localOptions = { + clipPlane: false, + useInstances: false, + ...options, + }; + + if (!this._uniformBufferLayoutBuilt) { + this.buildUniformLayout(); + } + + this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); + const checkReady = () => { + if (this._breakShaderLoadedCheck) { + return; + } + + const defines = new OpenPBRMaterialDefines({ + ...(this._eventInfo.defineNames || {}), + ...(this._samplerDefines || {}), + }); + const effect = this._prepareEffect(mesh, defines, undefined, undefined, localOptions.useInstances, localOptions.clipPlane, mesh.hasThinInstances)!; + if (this._onEffectCreatedObservable) { + onCreatedEffectParameters.effect = effect; + onCreatedEffectParameters.subMesh = null; + this._onEffectCreatedObservable.notifyObservers(onCreatedEffectParameters); + } + if (effect.isReady()) { + if (onCompiled) { + onCompiled(this); + } + } else { + effect.onCompileObservable.add(() => { + if (onCompiled) { + onCompiled(this); + } + }); + } + }; + checkReady(); + } + + /** + * Specifies that the submesh is ready to be used. + * @param mesh - BJS mesh. + * @param subMesh - A submesh of the BJS mesh. Used to check if it is ready. + * @param useInstances - Specifies that instances should be used. + * @returns - boolean indicating that the submesh is ready or not. + */ + public override isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean { + if (!this._uniformBufferLayoutBuilt) { + this.buildUniformLayout(); + } + + const drawWrapper = subMesh._drawWrapper; + + if (drawWrapper.effect && this.isFrozen) { + if (drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) { + return true; + } + } + + if (!subMesh.materialDefines) { + this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); + subMesh.materialDefines = new OpenPBRMaterialDefines({ + ...(this._eventInfo.defineNames || {}), + ...(this._samplerDefines || {}), + }); + } + + const defines = subMesh.materialDefines; + if (this._isReadyForSubMesh(subMesh)) { + return true; + } + + const scene = this.getScene(); + const engine = scene.getEngine(); + + if (defines._areTexturesDirty) { + this._eventInfo.hasRenderTargetTextures = false; + this._callbackPluginEventHasRenderTargetTextures(this._eventInfo); + this._cacheHasRenderTargetTextures = this._eventInfo.hasRenderTargetTextures; + if (scene.texturesEnabled) { + // Loop through samplers, check MaterialFlag and whether the texture is ready or not. + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value) { + if (!sampler.value.isReadyOrNotBlocking()) { + return false; + } + } + } + + const reflectionTexture = this._getReflectionTexture(); + if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { + if (!reflectionTexture.isReadyOrNotBlocking()) { + return false; + } + if (reflectionTexture.irradianceTexture) { + if (!reflectionTexture.irradianceTexture.isReadyOrNotBlocking()) { + return false; + } + } else { + // Not ready until spherical are ready too. + if (!reflectionTexture.sphericalPolynomial && reflectionTexture.getInternalTexture()?._sphericalPolynomialPromise) { + return false; + } + } + } + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + if (!this._lightmapTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + // Bump texture cannot be not blocking. + if (!this._bumpTexture.isReady()) { + return false; + } + } + + if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) { + // This is blocking. + if (!this._environmentBRDFTexture.isReady()) { + return false; + } + } + } + } + + this._eventInfo.isReadyForSubMesh = true; + this._eventInfo.defines = defines; + this._eventInfo.subMesh = subMesh; + this._callbackPluginEventIsReadyForSubMesh(this._eventInfo); + + if (!this._eventInfo.isReadyForSubMesh) { + return false; + } + + if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) { + if (!this._imageProcessingConfiguration.isReady()) { + return false; + } + } + + // Check if Area Lights have LTC texture. + if (defines["AREALIGHTUSED"]) { + for (let index = 0; index < mesh.lightSources.length; index++) { + if (!mesh.lightSources[index]._isReady()) { + return false; + } + } + } + + if (!engine.getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) { + mesh.createNormals(true); + Logger.Warn("OpenPBRMaterial: Normals have been created for the mesh: " + mesh.name); + } + + const previousEffect = subMesh.effect; + const lightDisposed = defines._areLightsDisposed; + let effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances, null, subMesh.getRenderingMesh().hasThinInstances); + + let forceWasNotReadyPreviously = false; + + if (effect) { + if (this._onEffectCreatedObservable) { + onCreatedEffectParameters.effect = effect; + onCreatedEffectParameters.subMesh = subMesh; + this._onEffectCreatedObservable.notifyObservers(onCreatedEffectParameters); + } + + // Use previous effect while new one is compiling + if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) { + effect = previousEffect; + defines.markAsUnprocessed(); + + forceWasNotReadyPreviously = this.isFrozen; + + if (lightDisposed) { + // re register in case it takes more than one frame. + defines._areLightsDisposed = true; + return false; + } + } else { + scene.resetCachedMaterial(); + subMesh.setEffect(effect, defines, this._materialContext); + } + } + + if (!subMesh.effect || !subMesh.effect.isReady()) { + return false; + } + + defines._renderId = scene.getRenderId(); + drawWrapper._wasPreviouslyReady = forceWasNotReadyPreviously ? false : true; + drawWrapper._wasPreviouslyUsingInstances = !!useInstances; + + this._checkScenePerformancePriority(); + + return true; + } + + /** + * Initializes the uniform buffer layout for the shader. + */ + public override buildUniformLayout(): void { + // Order is important ! + const ubo = this._uniformBuffer; + ubo.addUniform("vLightmapInfos", 2); + ubo.addUniform("vBumpInfos", 3); + ubo.addUniform("lightmapMatrix", 16); + ubo.addUniform("bumpMatrix", 16); + ubo.addUniform("vTangentSpaceParams", 2); + ubo.addUniform("vLightingIntensity", 4); + + ubo.addUniform("pointSize", 1); + + ubo.addUniform("vDebugMode", 2); + + ubo.addUniform("cameraInfo", 4); + PrepareUniformLayoutForIBL(ubo, true, true, true, true, true); + + Object.values(this._uniformsList).forEach((uniform) => { + ubo.addUniform(uniform.name, uniform.numComponents); + }); + + Object.values(this._samplersList).forEach((sampler) => { + ubo.addUniform(sampler.samplerInfoName, 2); + ubo.addUniform(sampler.samplerMatrixName, 16); + }); + + super.buildUniformLayout(); + } + + /** + * Binds the submesh data. + * @param world - The world matrix. + * @param mesh - The BJS mesh. + * @param subMesh - A submesh of the BJS mesh. + */ + public override bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void { + const scene = this.getScene(); + + const defines = subMesh.materialDefines; + if (!defines) { + return; + } + + const effect = subMesh.effect; + + if (!effect) { + return; + } + + this._activeEffect = effect; + + // Matrices Mesh. + mesh.getMeshUniformBuffer().bindToEffect(effect, "Mesh"); + mesh.transferToEffect(world); + + const engine = scene.getEngine(); + + // Binding unconditionally + this._uniformBuffer.bindToEffect(effect, "Material"); + + this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen); + + MaterialHelperGeometryRendering.Bind(engine.currentRenderPassId, this._activeEffect, mesh, world, this); + + const camera = scene.activeCamera; + if (camera) { + this._uniformBuffer.updateFloat4("cameraInfo", camera.minZ, camera.maxZ, 0, 0); + } else { + this._uniformBuffer.updateFloat4("cameraInfo", 0, 0, 0, 0); + } + + this._eventInfo.subMesh = subMesh; + this._callbackPluginEventHardBindForSubMesh(this._eventInfo); + + // Normal Matrix + if (defines.OBJECTSPACE_NORMALMAP) { + world.toNormalMatrix(this._normalMatrix); + this.bindOnlyNormalMatrix(this._normalMatrix); + } + + const mustRebind = this._mustRebind(scene, effect, subMesh, mesh.visibility); + + // Bones + BindBonesParameters(mesh, this._activeEffect, this.prePassConfiguration); + + let reflectionTexture: Nullable = null; + const ubo = this._uniformBuffer; + if (mustRebind) { + this.bindViewProjection(effect); + reflectionTexture = this._getReflectionTexture(); + + if (!ubo.useUbo || !this.isFrozen || !ubo.isSync || subMesh._drawWrapper._forceRebindOnNextCall) { + // Texture uniforms + if (scene.texturesEnabled) { + // Loop through samplers and bind info and matrix for each texture. + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value) { + ubo.updateFloat2(sampler.samplerInfoName, sampler.value.coordinatesIndex, sampler.value.level); + BindTextureMatrix(sampler.value, ubo, sampler.samplerPrefix); + } + } + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level); + BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); + } + + if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + ubo.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, this._bumpTexture.level, this._parallaxScaleBias); + BindTextureMatrix(this._bumpTexture, ubo, "bump"); + + if (scene._mirroredCameraPosition) { + ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0); + } else { + ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? -1.0 : 1.0, this._invertNormalMapY ? -1.0 : 1.0); + } + } + } + + BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, true, true, true, true, true, this._reflectionColor); + + // Point size + if (this.pointsCloud) { + ubo.updateFloat("pointSize", this.pointSize); + } + + Object.values(this._uniformsList).forEach((uniform) => { + // If the property actually defines a uniform, update it. + if (uniform.numComponents === 4) { + uniform.populateVectorFromLinkedProperties(TmpVectors.Vector4[0]); + ubo.updateVector4(uniform.name, TmpVectors.Vector4[0]); + } else if (uniform.numComponents === 3) { + uniform.populateVectorFromLinkedProperties(TmpVectors.Vector3[0]); + ubo.updateVector3(uniform.name, TmpVectors.Vector3[0]); + } else if (uniform.numComponents === 2) { + uniform.populateVectorFromLinkedProperties(TmpVectors.Vector2[0]); + ubo.updateFloat2(uniform.name, TmpVectors.Vector2[0].x, TmpVectors.Vector2[0].y); + } else if (uniform.numComponents === 1) { + ubo.updateFloat(uniform.name, uniform.linkedProperties[Object.keys(uniform.linkedProperties)[0]].value); + } + }); + + // Misc + this._lightingInfos.x = this._directIntensity; + this._lightingInfos.y = this._emissiveIntensity; + this._lightingInfos.z = this._environmentIntensity * scene.environmentIntensity; + this._lightingInfos.w = 1.0; // This is used to be _specularIntensity. + + ubo.updateVector4("vLightingIntensity", this._lightingInfos); + + ubo.updateFloat2("vDebugMode", this.debugLimit, this.debugFactor); + } + + // Textures + if (scene.texturesEnabled) { + // Loop through samplers and set textures + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value) { + ubo.setTexture(sampler.samplerName, sampler.value); + } + } + + BindIBLSamplers(scene, defines, ubo, reflectionTexture, this.realTimeFiltering); + + if (defines.ENVIRONMENTBRDF) { + ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); + } + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + ubo.setTexture("lightmapSampler", this._lightmapTexture); + } + + if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + ubo.setTexture("bumpSampler", this._bumpTexture); + } + } + + // OIT with depth peeling + if (this.getScene().useOrderIndependentTransparency && this.needAlphaBlendingForMesh(mesh)) { + this.getScene().depthPeelingRenderer!.bind(effect); + } + + this._eventInfo.subMesh = subMesh; + this._callbackPluginEventBindForSubMesh(this._eventInfo); + + // Clip plane + BindClipPlane(this._activeEffect, this, scene); + + this.bindEyePosition(effect); + } else if (scene.getEngine()._features.needToAlwaysBindUniformBuffers) { + this._needToBindSceneUbo = true; + } + + if (mustRebind || !this.isFrozen) { + // Lights + if (scene.lightsEnabled && !this._disableLighting) { + BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights); + } + + // View + if ((scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) || reflectionTexture || mesh.receiveShadows || defines.PREPASS) { + this.bindView(effect); + } + + // Fog + BindFogParameters(scene, mesh, this._activeEffect, true); + + // Morph targets + if (defines.NUM_MORPH_INFLUENCERS) { + BindMorphTargetParameters(mesh, this._activeEffect); + } + + if (defines.BAKED_VERTEX_ANIMATION_TEXTURE) { + mesh.bakedVertexAnimationManager?.bind(effect, defines.INSTANCES); + } + + // image processing + this._imageProcessingConfiguration.bind(this._activeEffect); + + // Log. depth + BindLogDepth(defines, this._activeEffect, scene); + } + + this._afterBind(mesh, this._activeEffect, subMesh); + + ubo.update(); + } + + /** + * Returns the animatable textures. + * If material have animatable metallic texture, then reflectivity texture will not be returned, even if it has animations. + * @returns - Array of animatable textures. + */ + public override getAnimatables(): IAnimatable[] { + const results = super.getAnimatables(); + + // Loop through samplers and push animated textures to list. + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value && sampler.value.animations && sampler.value.animations.length > 0) { + results.push(sampler.value); + } + } + + if (this._reflectionTexture && this._reflectionTexture.animations && this._reflectionTexture.animations.length > 0) { + results.push(this._reflectionTexture); + } + + if (this._bumpTexture && this._bumpTexture.animations && this._bumpTexture.animations.length > 0) { + results.push(this._bumpTexture); + } + + if (this._lightmapTexture && this._lightmapTexture.animations && this._lightmapTexture.animations.length > 0) { + results.push(this._lightmapTexture); + } + + return results; + } + + /** + * Returns an array of the actively used textures. + * @returns - Array of BaseTextures + */ + public override getActiveTextures(): BaseTexture[] { + const activeTextures = super.getActiveTextures(); + + // Loop through samplers and push active textures + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value) { + activeTextures.push(sampler.value); + } + } + + if (this._reflectionTexture) { + activeTextures.push(this._reflectionTexture); + } + + if (this._bumpTexture) { + activeTextures.push(this._bumpTexture); + } + + if (this._lightmapTexture) { + activeTextures.push(this._lightmapTexture); + } + + return activeTextures; + } + + /** + * Checks to see if a texture is used in the material. + * @param texture - Base texture to use. + * @returns - Boolean specifying if a texture is used in the material. + */ + public override hasTexture(texture: BaseTexture): boolean { + if (super.hasTexture(texture)) { + return true; + } + + // Loop through samplers and check each texture for equality + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value === texture) { + return true; + } + } + + if (this._reflectionTexture === texture) { + return true; + } + + if (this._bumpTexture === texture) { + return true; + } + + if (this._lightmapTexture === texture) { + return true; + } + + return false; + } + + /** + * Sets the required values to the prepass renderer. + * It can't be sets when subsurface scattering of this material is disabled. + * When scene have ability to enable subsurface prepass effect, it will enable. + * @returns - If prepass is enabled or not. + */ + public override setPrePassRenderer(): boolean { + return false; + } + + /** + * Disposes the resources of the material. + * @param forceDisposeEffect - Forces the disposal of effects. + * @param forceDisposeTextures - Forces the disposal of all textures. + */ + public override dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void { + this._breakShaderLoadedCheck = true; + if (forceDisposeTextures) { + if (this._environmentBRDFTexture && this.getScene().environmentBRDFTexture !== this._environmentBRDFTexture) { + this._environmentBRDFTexture.dispose(); + } + + // Loop through samplers and dispose the textures + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + sampler.value?.dispose(); + } + + this._reflectionTexture?.dispose(); + this._bumpTexture?.dispose(); + this._lightmapTexture?.dispose(); + } + + this._renderTargets.dispose(); + + if (this._imageProcessingConfiguration && this._imageProcessingObserver) { + this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); + } + + super.dispose(forceDisposeEffect, forceDisposeTextures); + } + + /** + * Returns the texture used for reflections. + * @returns - Reflection texture if present. Otherwise, returns the environment texture. + */ + private _getReflectionTexture(): Nullable { + if (this._reflectionTexture) { + return this._reflectionTexture; + } + + return this.getScene().environmentTexture; + } + + private _prepareEffect( + mesh: AbstractMesh, + defines: OpenPBRMaterialDefines, + onCompiled: Nullable<(effect: Effect) => void> = null, + onError: Nullable<(effect: Effect, errors: string) => void> = null, + useInstances: Nullable = null, + useClipPlane: Nullable = null, + useThinInstances: boolean + ): Nullable { + this._prepareDefines(mesh, defines, useInstances, useClipPlane, useThinInstances); + + if (!defines.isDirty) { + return null; + } + + defines.markAsProcessed(); + + const scene = this.getScene(); + const engine = scene.getEngine(); + + // Fallbacks + const fallbacks = new EffectFallbacks(); + let fallbackRank = 0; + if (defines.USESPHERICALINVERTEX) { + fallbacks.addFallback(fallbackRank++, "USESPHERICALINVERTEX"); + } + + if (defines.FOG) { + fallbacks.addFallback(fallbackRank, "FOG"); + } + if (defines.SPECULARAA) { + fallbacks.addFallback(fallbackRank, "SPECULARAA"); + } + if (defines.POINTSIZE) { + fallbacks.addFallback(fallbackRank, "POINTSIZE"); + } + if (defines.LOGARITHMICDEPTH) { + fallbacks.addFallback(fallbackRank, "LOGARITHMICDEPTH"); + } + if (defines.PARALLAX) { + fallbacks.addFallback(fallbackRank, "PARALLAX"); + } + if (defines.PARALLAX_RHS) { + fallbacks.addFallback(fallbackRank, "PARALLAX_RHS"); + } + if (defines.PARALLAXOCCLUSION) { + fallbacks.addFallback(fallbackRank++, "PARALLAXOCCLUSION"); + } + + if (defines.ENVIRONMENTBRDF) { + fallbacks.addFallback(fallbackRank++, "ENVIRONMENTBRDF"); + } + + if (defines.TANGENT) { + fallbacks.addFallback(fallbackRank++, "TANGENT"); + } + + if (defines.BUMP) { + fallbacks.addFallback(fallbackRank++, "BUMP"); + } + + fallbackRank = HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights, fallbackRank++); + + if (defines.SPECULARTERM) { + fallbacks.addFallback(fallbackRank++, "SPECULARTERM"); + } + + if (defines.USESPHERICALFROMREFLECTIONMAP) { + fallbacks.addFallback(fallbackRank++, "USESPHERICALFROMREFLECTIONMAP"); + } + + if (defines.USEIRRADIANCEMAP) { + fallbacks.addFallback(fallbackRank++, "USEIRRADIANCEMAP"); + } + + if (defines.LIGHTMAP) { + fallbacks.addFallback(fallbackRank++, "LIGHTMAP"); + } + + if (defines.NORMAL) { + fallbacks.addFallback(fallbackRank++, "NORMAL"); + } + + if (defines.VERTEXCOLOR) { + fallbacks.addFallback(fallbackRank++, "VERTEXCOLOR"); + } + + if (defines.MORPHTARGETS) { + fallbacks.addFallback(fallbackRank++, "MORPHTARGETS"); + } + + if (defines.MULTIVIEW) { + fallbacks.addFallback(0, "MULTIVIEW"); + } + + //Attributes + const attribs = [VertexBuffer.PositionKind]; + + if (defines.NORMAL) { + attribs.push(VertexBuffer.NormalKind); + } + + if (defines.TANGENT) { + attribs.push(VertexBuffer.TangentKind); + } + + for (let i = 1; i <= Constants.MAX_SUPPORTED_UV_SETS; ++i) { + if (defines["UV" + i]) { + attribs.push(`uv${i === 1 ? "" : i}`); + } + } + + if (defines.VERTEXCOLOR) { + attribs.push(VertexBuffer.ColorKind); + } + + PrepareAttributesForBones(attribs, mesh, defines, fallbacks); + PrepareAttributesForInstances(attribs, defines); + PrepareAttributesForMorphTargets(attribs, mesh, defines); + PrepareAttributesForBakedVertexAnimation(attribs, mesh, defines); + + let shaderName = "openpbr"; + + const uniforms = [ + "world", + "view", + "viewProjection", + "vEyePosition", + "vLightsType", + "visibility", + "vFogInfos", + "vFogColor", + "pointSize", + "vBumpInfos", + "vLightmapInfos", + "mBones", + "normalMatrix", + "bumpMatrix", + "lightmapMatrix", + "vLightingIntensity", + "logarithmicDepthConstant", + "vTangentSpaceParams", + "boneTextureWidth", + "vDebugMode", + "morphTargetTextureInfo", + "morphTargetTextureIndices", + "cameraInfo", + ]; + + for (const uniformName in Object.keys(this._uniformsList)) { + uniforms.push(uniformName); + } + + const samplers = [ + "reflectivitySampler", + "bumpSampler", + "lightmapSampler", + "environmentBrdfSampler", + "boneSampler", + "metallicReflectanceSampler", + "reflectanceSampler", + "morphTargets", + "oitDepthSampler", + "oitFrontColorSampler", + "areaLightsLTC1Sampler", + "areaLightsLTC2Sampler", + ]; + + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + samplers.push(sampler.samplerName); + } + + PrepareUniformsAndSamplersForIBL(uniforms, samplers, true); + + const uniformBuffers = ["Material", "Scene", "Mesh"]; + + const indexParameters = { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }; + + this._eventInfo.fallbacks = fallbacks; + this._eventInfo.fallbackRank = fallbackRank; + this._eventInfo.defines = defines; + this._eventInfo.uniforms = uniforms; + this._eventInfo.attributes = attribs; + this._eventInfo.samplers = samplers; + this._eventInfo.uniformBuffersNames = uniformBuffers; + this._eventInfo.customCode = undefined; + this._eventInfo.mesh = mesh; + this._eventInfo.indexParameters = indexParameters; + this._callbackPluginEventGeneric(MaterialPluginEvent.PrepareEffect, this._eventInfo); + + MaterialHelperGeometryRendering.AddUniformsAndSamplers(uniforms, samplers); + + PrePassConfiguration.AddUniforms(uniforms); + PrePassConfiguration.AddSamplers(samplers); + AddClipPlaneUniforms(uniforms); + + if (ImageProcessingConfiguration) { + ImageProcessingConfiguration.PrepareUniforms(uniforms, defines); + ImageProcessingConfiguration.PrepareSamplers(samplers, defines); + } + + PrepareUniformsAndSamplersList({ + uniformsNames: uniforms, + uniformBuffersNames: uniformBuffers, + samplers: samplers, + defines: defines, + maxSimultaneousLights: this._maxSimultaneousLights, + }); + + const csnrOptions: ICustomShaderNameResolveOptions = {}; + + if (this.customShaderNameResolve) { + shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs, csnrOptions); + } + + const join = defines.toString(); + const effect = engine.createEffect( + shaderName, + { + attributes: attribs, + uniformsNames: uniforms, + uniformBuffersNames: uniformBuffers, + samplers: samplers, + defines: join, + fallbacks: fallbacks, + onCompiled: onCompiled, + onError: onError, + indexParameters, + processFinalCode: csnrOptions.processFinalCode, + processCodeAfterIncludes: this._eventInfo.customCode, + multiTarget: defines.PREPASS, + shaderLanguage: this._shaderLanguage, + extraInitializationsAsync: this._shadersLoaded + ? undefined + : async () => { + if (this.shaderLanguage === ShaderLanguage.WGSL) { + await Promise.all([import("../../ShadersWGSL/openpbr.vertex"), import("../../ShadersWGSL/openpbr.fragment")]); + } else { + await Promise.all([import("../../Shaders/openpbr.vertex"), import("../../Shaders/openpbr.fragment")]); + } + + this._shadersLoaded = true; + }, + }, + engine + ); + + this._eventInfo.customCode = undefined; + + return effect; + } + + private _prepareDefines( + mesh: AbstractMesh, + defines: OpenPBRMaterialDefines, + useInstances: Nullable = null, + useClipPlane: Nullable = null, + useThinInstances: boolean = false + ): void { + const scene = this.getScene(); + const engine = scene.getEngine(); + + // Lights + PrepareDefinesForLights(scene, mesh, defines, true, this._maxSimultaneousLights, this._disableLighting); + defines._needNormals = true; + + // Multiview + PrepareDefinesForMultiview(scene, defines); + + // PrePass + const oit = this.needAlphaBlendingForMesh(mesh) && this.getScene().useOrderIndependentTransparency; + PrepareDefinesForPrePass(scene, defines, this.canRenderToMRT && !oit); + + // Order independant transparency + PrepareDefinesForOIT(scene, defines, oit); + + MaterialHelperGeometryRendering.PrepareDefines(engine.currentRenderPassId, mesh, defines); + + // Textures + defines.METALLICWORKFLOW = true; + if (defines._areTexturesDirty) { + defines._needUVs = false; + for (let i = 1; i <= Constants.MAX_SUPPORTED_UV_SETS; ++i) { + defines["MAINUV" + i] = false; + } + if (scene.texturesEnabled) { + defines.AMBIENTDIRECTUV = 0; + defines.OPACITYDIRECTUV = 0; + defines.EMISSIVEDIRECTUV = 0; + defines.REFLECTIVITYDIRECTUV = 0; + defines.METALLIC_REFLECTANCEDIRECTUV = 0; + defines.REFLECTANCEDIRECTUV = 0; + defines.BUMPDIRECTUV = 0; + defines.LIGHTMAPDIRECTUV = 0; + + if (engine.getCaps().textureLOD) { + defines.LODBASEDMICROSFURACE = true; + } + + // TODO - loop through samplers and prepare defines for each texture + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + if (sampler.value) { + PrepareDefinesForMergedUV(sampler.value, defines, sampler.textureDefine); + defines[sampler.textureDefine + "_GAMMA"] = sampler.value.gammaSpace; + } else { + defines[sampler.textureDefine] = false; + } + } + + const reflectionTexture = this._getReflectionTexture(); + const useSHInFragment: boolean = + this._forceIrradianceInFragment || + this.realTimeFiltering || + this._twoSidedLighting || + engine.getCaps().maxVaryingVectors <= 8 || + this._baseDiffuseRoughnessTexture != null; + PrepareDefinesForIBL(scene, reflectionTexture, defines, this.realTimeFiltering, this.realTimeFilteringQuality, !useSHInFragment); + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + PrepareDefinesForMergedUV(this._lightmapTexture, defines, "LIGHTMAP"); + defines.USELIGHTMAPASSHADOWMAP = this._useLightmapAsShadowmap; + defines.GAMMALIGHTMAP = this._lightmapTexture.gammaSpace; + defines.RGBDLIGHTMAP = this._lightmapTexture.isRGBD; + } else { + defines.LIGHTMAP = false; + } + + if (MaterialFlags.SpecularTextureEnabled) { + if (this._baseMetalRoughTexture) { + defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed; + } + + defines.SPECULAR_WEIGHT_USE_ALPHA_ONLY = this._useSpecularWeightFromTextureAlpha; + } + + if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + PrepareDefinesForMergedUV(this._bumpTexture, defines, "BUMP"); + + if (this._useParallax && this.baseColorTexture && MaterialFlags.DiffuseTextureEnabled) { + defines.PARALLAX = true; + defines.PARALLAX_RHS = scene.useRightHandedSystem; + defines.PARALLAXOCCLUSION = !!this._useParallaxOcclusion; + } else { + defines.PARALLAX = false; + } + + defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap; + } else { + defines.BUMP = false; + defines.PARALLAX = false; + defines.PARALLAX_RHS = false; + defines.PARALLAXOCCLUSION = false; + defines.OBJECTSPACE_NORMALMAP = false; + } + + if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) { + defines.ENVIRONMENTBRDF = true; + defines.ENVIRONMENTBRDF_RGBD = this._environmentBRDFTexture.isRGBD; + } else { + defines.ENVIRONMENTBRDF = false; + defines.ENVIRONMENTBRDF_RGBD = false; + } + + if (this._shouldUseAlphaFromAlbedoTexture()) { + defines.ALPHAFROMALBEDO = true; + } else { + defines.ALPHAFROMALBEDO = false; + } + } + + defines.SPECULAROVERALPHA = this._useSpecularOverAlpha; + + if (this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_STANDARD) { + defines.USEPHYSICALLIGHTFALLOFF = false; + defines.USEGLTFLIGHTFALLOFF = false; + } else if (this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_GLTF) { + defines.USEPHYSICALLIGHTFALLOFF = false; + defines.USEGLTFLIGHTFALLOFF = true; + } else { + defines.USEPHYSICALLIGHTFALLOFF = true; + defines.USEGLTFLIGHTFALLOFF = false; + } + + defines.RADIANCEOVERALPHA = this._useRadianceOverAlpha; + + if (!this.backFaceCulling && this._twoSidedLighting) { + defines.TWOSIDEDLIGHTING = true; + } else { + defines.TWOSIDEDLIGHTING = false; + } + + // We need it to not invert normals in two sided lighting mode (based on the winding of the face) + defines.MIRRORED = !!scene._mirroredCameraPosition; + + defines.SPECULARAA = engine.getCaps().standardDerivatives && this._enableSpecularAntiAliasing; + } + + if (defines._areTexturesDirty || defines._areMiscDirty) { + defines.ALPHATESTVALUE = `${this._alphaCutOff}${this._alphaCutOff % 1 === 0 ? "." : ""}`; + defines.PREMULTIPLYALPHA = this.alphaMode === Constants.ALPHA_PREMULTIPLIED || this.alphaMode === Constants.ALPHA_PREMULTIPLIED_PORTERDUFF; + defines.ALPHABLEND = this.needAlphaBlendingForMesh(mesh); + } + + if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) { + this._imageProcessingConfiguration.prepareDefines(defines); + } + + defines.FORCENORMALFORWARD = this._forceNormalForward; + + defines.RADIANCEOCCLUSION = this._useRadianceOcclusion; + + defines.HORIZONOCCLUSION = this._useHorizonOcclusion; + + // Misc. + if (defines._areMiscDirty) { + PrepareDefinesForMisc( + mesh, + scene, + this._useLogarithmicDepth, + this.pointsCloud, + this.fogEnabled, + this.needAlphaTestingForMesh(mesh), + defines, + this._applyDecalMapAfterDetailMap + ); + defines.UNLIT = this._unlit || ((this.pointsCloud || this.wireframe) && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)); + defines.DEBUGMODE = this._debugMode; + } + + // Values that need to be evaluated on every frame + PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances ? true : false, useClipPlane, useThinInstances); + + // External config + this._eventInfo.defines = defines; + this._eventInfo.mesh = mesh; + this._callbackPluginEventPrepareDefinesBeforeAttributes(this._eventInfo); + + // Attribs + PrepareDefinesForAttributes(mesh, defines, true, true, true, this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE); + + // External config + this._callbackPluginEventPrepareDefines(this._eventInfo); + } +} + +RegisterClass("BABYLON.OpenPBRMaterial", OpenPBRMaterial); diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index 841eab9fb71..711a8d62c65 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { serializeAsImageProcessingConfiguration, expandToProperty } from "../../Misc/decorators"; -import type { Observer } from "../../Misc/observable"; +import { expandToProperty } from "../../Misc/decorators"; import { Logger } from "../../Misc/logger"; import { SmartArray } from "../../Misc/smartArray"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; @@ -16,7 +15,7 @@ import { PBRBRDFConfiguration } from "./pbrBRDFConfiguration"; import { PrePassConfiguration } from "../prePassConfiguration"; import { Color3, TmpColors } from "../../Maths/math.color"; -import type { IImageProcessingConfigurationDefines } from "../../Materials/imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration"; import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../../Materials/material"; @@ -26,9 +25,7 @@ import { MaterialDefines } from "../../Materials/materialDefines"; import { PushMaterial } from "../../Materials/pushMaterial"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; -import { Texture } from "../../Materials/Textures/texture"; import type { RenderTargetTexture } from "../../Materials/Textures/renderTargetTexture"; -import type { CubeTexture } from "../../Materials/Textures/cubeTexture"; import { MaterialFlags } from "../materialFlags"; import { Constants } from "../../Engines/constants"; @@ -51,6 +48,8 @@ import { BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, + BindIBLParameters, + BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, @@ -59,40 +58,35 @@ import { PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, + PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, PrepareUniformsAndSamplersList, + PrepareUniformsAndSamplersForIBL, + PrepareUniformLayoutForIBL, } from "../materialHelper.functions"; import { ShaderLanguage } from "../shaderLanguage"; import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering"; +import { UVDefinesMixin } from "../uv.defines"; +import { ImageProcessingMixin } from "../imageProcessing"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; +class PBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} + /** * Manages the defines for the PBR Material. * @internal */ -export class PBRMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +export class PBRMaterialDefines extends ImageProcessingDefinesMixin(PBRMaterialDefinesBase) { public PBR = true; public NUM_SAMPLES = "0"; public REALTIME_FILTERING = false; public IBL_CDF_FILTERING = false; - public MAINUV1 = false; - public MAINUV2 = false; - public MAINUV3 = false; - public MAINUV4 = false; - public MAINUV5 = false; - public MAINUV6 = false; - public UV1 = false; - public UV2 = false; - public UV3 = false; - public UV4 = false; - public UV5 = false; - public UV6 = false; public ALBEDO = false; public GAMMAALBEDO = false; @@ -256,25 +250,6 @@ export class PBRMaterialDefines extends MaterialDefines implements IImageProcess public NUM_MORPH_INFLUENCERS = 0; public MORPHTARGETS_TEXTURE = false; - public IMAGEPROCESSING = false; - public VIGNETTE = false; - public VIGNETTEBLENDMODEMULTIPLY = false; - public VIGNETTEBLENDMODEOPAQUE = false; - public TONEMAPPING = 0; - public CONTRAST = false; - public COLORCURVES = false; - public COLORGRADING = false; - public COLORGRADING3D = false; - public SAMPLER3DGREENDEPTH = false; - public SAMPLER3DBGRMAP = false; - public DITHER = false; - public IMAGEPROCESSINGPOSTPROCESS = false; - public SKIPFINALCOLORCLAMP = false; - public EXPOSURE = false; - public MULTIVIEW = false; - public ORDER_INDEPENDENT_TRANSPARENCY = false; - public ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false; - public USEPHYSICALLIGHTFALLOFF = false; public USEGLTFLIGHTFALLOFF = false; public TWOSIDEDLIGHTING = false; @@ -323,6 +298,7 @@ export class PBRMaterialDefines extends MaterialDefines implements IImageProcess } } +class PBRBaseMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * The Physically based material base class of BJS. * @@ -332,7 +308,7 @@ export class PBRMaterialDefines extends MaterialDefines implements IImageProcess * @see [WebGL](https://playground.babylonjs.com/#CGHTSM#1) * @see [WebGPU](https://playground.babylonjs.com/#CGHTSM#2) */ -export abstract class PBRBaseMaterial extends PushMaterial { +export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { /** * PBRMaterialTransparencyMode: No transparency mode, Alpha channel is not use. */ @@ -842,46 +818,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { */ public _enableSpecularAntiAliasing = false; - /** - * Default configuration related to image processing available in the PBR Material. - */ - @serializeAsImageProcessingConfiguration() - protected _imageProcessingConfiguration: ImageProcessingConfiguration; - - /** - * Keep track of the image processing observer to allow dispose and replace. - */ - private _imageProcessingObserver: Nullable> = null; - - /** - * Attaches a new image processing configuration to the PBR Material. - * @param configuration - */ - protected _attachImageProcessingConfiguration(configuration: Nullable): void { - if (configuration === this._imageProcessingConfiguration) { - return; - } - - // Detaches observer. - if (this._imageProcessingConfiguration && this._imageProcessingObserver) { - this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); - } - - // Pick the scene configuration if needed. - if (!configuration) { - this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration; - } else { - this._imageProcessingConfiguration = configuration; - } - - // Attaches observer. - if (this._imageProcessingConfiguration) { - this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { - this._markAllSubMeshesAsImageProcessingDirty(); - }); - } - } - /** * Stores the available render targets. */ @@ -1474,7 +1410,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { "vMetallicReflectanceFactors", "vEmissiveColor", "visibility", - "vReflectionColor", "vFogInfos", "vFogColor", "pointSize", @@ -1483,12 +1418,8 @@ export abstract class PBRBaseMaterial extends PushMaterial { "vBaseDiffuseRoughnessInfos", "vAmbientInfos", "vOpacityInfos", - "vReflectionInfos", - "vReflectionPosition", - "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", - "vReflectionFilteringInfo", "vMetallicReflectanceInfos", "vReflectanceInfos", "vMicroSurfaceSamplerInfos", @@ -1500,7 +1431,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { "baseDiffuseRoughnessMatrix", "ambientMatrix", "opacityMatrix", - "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", @@ -1511,26 +1441,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { "reflectanceMatrix", "vLightingIntensity", "logarithmicDepthConstant", - "vSphericalX", - "vSphericalY", - "vSphericalZ", - "vSphericalXX_ZZ", - "vSphericalYY_ZZ", - "vSphericalZZ", - "vSphericalXY", - "vSphericalYZ", - "vSphericalZX", - "vSphericalL00", - "vSphericalL1_1", - "vSphericalL10", - "vSphericalL11", - "vSphericalL2_2", - "vSphericalL2_1", - "vSphericalL20", - "vSphericalL21", - "vSphericalL22", - "vReflectionMicrosurfaceInfos", - "vReflectionDominantDirection", "vTangentSpaceParams", "boneTextureWidth", "vDebugMode", @@ -1549,10 +1459,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { "bumpSampler", "lightmapSampler", "opacitySampler", - "reflectionSampler", - "reflectionSamplerLow", - "reflectionSamplerHigh", - "irradianceSampler", "microSurfaceSampler", "environmentBrdfSampler", "boneSampler", @@ -1561,11 +1467,12 @@ export abstract class PBRBaseMaterial extends PushMaterial { "morphTargets", "oitDepthSampler", "oitFrontColorSampler", - "icdfSampler", "areaLightsLTC1Sampler", "areaLightsLTC2Sampler", ]; + PrepareUniformsAndSamplersForIBL(uniforms, samplers, true); + const uniformBuffers = ["Material", "Scene", "Mesh"]; const indexParameters = { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }; @@ -1729,126 +1636,13 @@ export abstract class PBRBaseMaterial extends PushMaterial { } const reflectionTexture = this._getReflectionTexture(); - if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - defines.REFLECTION = true; - defines.GAMMAREFLECTION = reflectionTexture.gammaSpace; - defines.RGBDREFLECTION = reflectionTexture.isRGBD; - defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha; - defines.LINEARSPECULARREFLECTION = reflectionTexture.linearSpecularLOD; - defines.USEIRRADIANCEMAP = false; - - if (this.realTimeFiltering && this.realTimeFilteringQuality > 0) { - defines.NUM_SAMPLES = "" + this.realTimeFilteringQuality; - if (engine._features.needTypeSuffixInShaderConstants) { - defines.NUM_SAMPLES = defines.NUM_SAMPLES + "u"; - } - - defines.REALTIME_FILTERING = true; - if (this.getScene().iblCdfGenerator) { - defines.IBL_CDF_FILTERING = true; - } - } else { - defines.REALTIME_FILTERING = false; - } - - defines.INVERTCUBICMAP = reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE; - defines.REFLECTIONMAP_3D = reflectionTexture.isCube; - defines.REFLECTIONMAP_OPPOSITEZ = defines.REFLECTIONMAP_3D && this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ; - - defines.REFLECTIONMAP_CUBIC = false; - defines.REFLECTIONMAP_EXPLICIT = false; - defines.REFLECTIONMAP_PLANAR = false; - defines.REFLECTIONMAP_PROJECTION = false; - defines.REFLECTIONMAP_SKYBOX = false; - defines.REFLECTIONMAP_SPHERICAL = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; - defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; - - switch (reflectionTexture.coordinatesMode) { - case Texture.EXPLICIT_MODE: - defines.REFLECTIONMAP_EXPLICIT = true; - break; - case Texture.PLANAR_MODE: - defines.REFLECTIONMAP_PLANAR = true; - break; - case Texture.PROJECTION_MODE: - defines.REFLECTIONMAP_PROJECTION = true; - break; - case Texture.SKYBOX_MODE: - defines.REFLECTIONMAP_SKYBOX = true; - break; - case Texture.SPHERICAL_MODE: - defines.REFLECTIONMAP_SPHERICAL = true; - break; - case Texture.EQUIRECTANGULAR_MODE: - defines.REFLECTIONMAP_EQUIRECTANGULAR = true; - break; - case Texture.FIXED_EQUIRECTANGULAR_MODE: - defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true; - break; - case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE: - defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true; - break; - case Texture.CUBIC_MODE: - case Texture.INVCUBIC_MODE: - default: - defines.REFLECTIONMAP_CUBIC = true; - defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (reflectionTexture).boundingBoxSize ? true : false; - break; - } - - if (reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) { - if (reflectionTexture.irradianceTexture) { - defines.USEIRRADIANCEMAP = true; - defines.USESPHERICALFROMREFLECTIONMAP = false; - defines.USESPHERICALINVERTEX = false; - if (reflectionTexture.irradianceTexture._dominantDirection) { - defines.USE_IRRADIANCE_DOMINANT_DIRECTION = true; - } - } - // Assume using spherical polynomial if the reflection texture is a cube map - else if (reflectionTexture.isCube) { - defines.USESPHERICALFROMREFLECTIONMAP = true; - defines.USEIRRADIANCEMAP = false; - defines.USE_IRRADIANCE_DOMINANT_DIRECTION = false; - if ( - this._forceIrradianceInFragment || - this.realTimeFiltering || - this._twoSidedLighting || - engine.getCaps().maxVaryingVectors <= 8 || - this._baseDiffuseRoughnessTexture - ) { - defines.USESPHERICALINVERTEX = false; - } else { - defines.USESPHERICALINVERTEX = true; - } - } - } - } else { - defines.REFLECTION = false; - defines.REFLECTIONMAP_3D = false; - defines.REFLECTIONMAP_SPHERICAL = false; - defines.REFLECTIONMAP_PLANAR = false; - defines.REFLECTIONMAP_CUBIC = false; - defines.USE_LOCAL_REFLECTIONMAP_CUBIC = false; - defines.REFLECTIONMAP_PROJECTION = false; - defines.REFLECTIONMAP_SKYBOX = false; - defines.REFLECTIONMAP_EXPLICIT = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR = false; - defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; - defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; - defines.INVERTCUBICMAP = false; - defines.USESPHERICALFROMREFLECTIONMAP = false; - defines.USEIRRADIANCEMAP = false; - defines.USE_IRRADIANCE_DOMINANT_DIRECTION = false; - defines.USESPHERICALINVERTEX = false; - defines.REFLECTIONMAP_OPPOSITEZ = false; - defines.LODINREFLECTIONALPHA = false; - defines.GAMMAREFLECTION = false; - defines.RGBDREFLECTION = false; - defines.LINEARSPECULARREFLECTION = false; - } + const useSHInFragment: boolean = + this._forceIrradianceInFragment || + this.realTimeFiltering || + this._twoSidedLighting || + engine.getCaps().maxVaryingVectors <= 8 || + this._baseDiffuseRoughnessTexture != null; + PrepareDefinesForIBL(scene, reflectionTexture, defines, this.realTimeFiltering, this.realTimeFilteringQuality, !useSHInFragment); if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { PrepareDefinesForMergedUV(this._lightmapTexture, defines, "LIGHTMAP"); @@ -2085,10 +1879,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { ubo.addUniform("vLightmapInfos", 2); ubo.addUniform("vReflectivityInfos", 3); ubo.addUniform("vMicroSurfaceSamplerInfos", 2); - ubo.addUniform("vReflectionInfos", 2); - ubo.addUniform("vReflectionFilteringInfo", 2); - ubo.addUniform("vReflectionPosition", 3); - ubo.addUniform("vReflectionSize", 3); ubo.addUniform("vBumpInfos", 3); ubo.addUniform("albedoMatrix", 16); ubo.addUniform("baseWeightMatrix", 16); @@ -2101,16 +1891,11 @@ export abstract class PBRBaseMaterial extends PushMaterial { ubo.addUniform("microSurfaceSamplerMatrix", 16); ubo.addUniform("bumpMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); - ubo.addUniform("reflectionMatrix", 16); - - ubo.addUniform("vReflectionColor", 3); ubo.addUniform("vAlbedoColor", 4); ubo.addUniform("baseWeight", 1); ubo.addUniform("baseDiffuseRoughness", 1); ubo.addUniform("vLightingIntensity", 4); - ubo.addUniform("vReflectionMicrosurfaceInfos", 3); - ubo.addUniform("vReflectionDominantDirection", 3); ubo.addUniform("pointSize", 1); ubo.addUniform("vReflectivityColor", 4); ubo.addUniform("vEmissiveColor", 3); @@ -2124,28 +1909,8 @@ export abstract class PBRBaseMaterial extends PushMaterial { ubo.addUniform("vReflectanceInfos", 2); ubo.addUniform("reflectanceMatrix", 16); - ubo.addUniform("vSphericalL00", 3); - ubo.addUniform("vSphericalL1_1", 3); - ubo.addUniform("vSphericalL10", 3); - ubo.addUniform("vSphericalL11", 3); - ubo.addUniform("vSphericalL2_2", 3); - ubo.addUniform("vSphericalL2_1", 3); - ubo.addUniform("vSphericalL20", 3); - ubo.addUniform("vSphericalL21", 3); - ubo.addUniform("vSphericalL22", 3); - - ubo.addUniform("vSphericalX", 3); - ubo.addUniform("vSphericalY", 3); - ubo.addUniform("vSphericalZ", 3); - ubo.addUniform("vSphericalXX_ZZ", 3); - ubo.addUniform("vSphericalYY_ZZ", 3); - ubo.addUniform("vSphericalZZ", 3); - ubo.addUniform("vSphericalXY", 3); - ubo.addUniform("vSphericalYZ", 3); - ubo.addUniform("vSphericalZX", 3); - ubo.addUniform("cameraInfo", 4); - + PrepareUniformLayoutForIBL(ubo, true, true, true, true, true); super.buildUniformLayout(); } @@ -2245,73 +2010,6 @@ export abstract class PBRBaseMaterial extends PushMaterial { BindTextureMatrix(this._opacityTexture, ubo, "opacity"); } - if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - ubo.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix()); - ubo.updateFloat2("vReflectionInfos", reflectionTexture.level * scene.iblIntensity, 0); - - if ((reflectionTexture).boundingBoxSize) { - const cubeTexture = reflectionTexture; - - ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition); - ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize); - } - - if (this.realTimeFiltering) { - const width = reflectionTexture.getSize().width; - ubo.updateFloat2("vReflectionFilteringInfo", width, Math.log2(width)); - } - - if (!defines.USEIRRADIANCEMAP) { - const polynomials = reflectionTexture.sphericalPolynomial; - if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) { - if (defines.SPHERICAL_HARMONICS) { - const preScaledHarmonics = polynomials.preScaledHarmonics; - ubo.updateVector3("vSphericalL00", preScaledHarmonics.l00); - ubo.updateVector3("vSphericalL1_1", preScaledHarmonics.l1_1); - ubo.updateVector3("vSphericalL10", preScaledHarmonics.l10); - ubo.updateVector3("vSphericalL11", preScaledHarmonics.l11); - ubo.updateVector3("vSphericalL2_2", preScaledHarmonics.l2_2); - ubo.updateVector3("vSphericalL2_1", preScaledHarmonics.l2_1); - ubo.updateVector3("vSphericalL20", preScaledHarmonics.l20); - ubo.updateVector3("vSphericalL21", preScaledHarmonics.l21); - ubo.updateVector3("vSphericalL22", preScaledHarmonics.l22); - } else { - ubo.updateFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z); - ubo.updateFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z); - ubo.updateFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z); - ubo.updateFloat3( - "vSphericalXX_ZZ", - polynomials.xx.x - polynomials.zz.x, - polynomials.xx.y - polynomials.zz.y, - polynomials.xx.z - polynomials.zz.z - ); - ubo.updateFloat3( - "vSphericalYY_ZZ", - polynomials.yy.x - polynomials.zz.x, - polynomials.yy.y - polynomials.zz.y, - polynomials.yy.z - polynomials.zz.z - ); - ubo.updateFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z); - ubo.updateFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z); - ubo.updateFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z); - ubo.updateFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z); - } - } - } else { - // If we're using an irradiance map with a dominant direction assigned, set it. - if (defines.USEIRRADIANCEMAP && defines.USE_IRRADIANCE_DOMINANT_DIRECTION) { - ubo.updateVector3("vReflectionDominantDirection", reflectionTexture.irradianceTexture!._dominantDirection!); - } - } - - ubo.updateFloat3( - "vReflectionMicrosurfaceInfos", - reflectionTexture.getSize().width, - reflectionTexture.lodGenerationScale, - reflectionTexture.lodGenerationOffset - ); - } - if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); BindTextureMatrix(this._emissiveTexture, ubo, "emissive"); @@ -2359,6 +2057,8 @@ export abstract class PBRBaseMaterial extends PushMaterial { } } + BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, true, true, true, true, true, this._reflectionColor); + // Point size if (this.pointsCloud) { ubo.updateFloat("pointSize", this.pointSize); @@ -2383,7 +2083,7 @@ export abstract class PBRBaseMaterial extends PushMaterial { } ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); - ubo.updateColor3("vReflectionColor", this._reflectionColor); + if (!defines.SS_REFRACTION && this.subSurface?._linkRefractionWithTransparency) { ubo.updateColor4("vAlbedoColor", this._albedoColor, 1); } else { @@ -2431,25 +2131,7 @@ export abstract class PBRBaseMaterial extends PushMaterial { ubo.setTexture("opacitySampler", this._opacityTexture); } - if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - if (defines.LODBASEDMICROSFURACE) { - ubo.setTexture("reflectionSampler", reflectionTexture); - } else { - ubo.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture); - ubo.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture); - ubo.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture); - } - - if (defines.USEIRRADIANCEMAP) { - ubo.setTexture("irradianceSampler", reflectionTexture.irradianceTexture); - } - - //if realtime filtering and using CDF maps, set them. - const cdfGenerator = this.getScene().iblCdfGenerator; - if (this.realTimeFiltering && cdfGenerator) { - ubo.setTexture("icdfSampler", cdfGenerator.getIcdfTexture()); - } - } + BindIBLSamplers(scene, defines, ubo, reflectionTexture, this.realTimeFiltering); if (defines.ENVIRONMENTBRDF) { ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); diff --git a/packages/dev/core/src/Materials/PBR/pbrMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrMaterial.ts index 212a3a0c30b..366acf92344 100644 --- a/packages/dev/core/src/Materials/PBR/pbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrMaterial.ts @@ -3,8 +3,6 @@ import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import type { Scene } from "../../scene"; import { Color3 } from "../../Maths/math.color"; -import type { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration"; -import type { ColorCurves } from "../../Materials/colorCurves"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; import { PBRBaseMaterial } from "./pbrBaseMaterial"; import { RegisterClass } from "../../Misc/typeStore"; @@ -657,127 +655,6 @@ export class PBRMaterial extends PBRBaseMaterial { @expandToProperty("_markAllSubMeshesAsMiscDirty") public applyDecalMapAfterDetailMap = false; - /** - * Gets the image processing configuration used either in this material. - */ - public get imageProcessingConfiguration(): ImageProcessingConfiguration { - return this._imageProcessingConfiguration; - } - - /** - * Sets the Default image processing configuration used either in the this material. - * - * If sets to null, the scene one is in use. - */ - public set imageProcessingConfiguration(value: ImageProcessingConfiguration) { - this._attachImageProcessingConfiguration(value); - - // Ensure the effect will be rebuilt. - this._markAllSubMeshesAsImageProcessingDirty(); - } - - /** - * Gets whether the color curves effect is enabled. - */ - public get cameraColorCurvesEnabled(): boolean { - return this.imageProcessingConfiguration.colorCurvesEnabled; - } - /** - * Sets whether the color curves effect is enabled. - */ - public set cameraColorCurvesEnabled(value: boolean) { - this.imageProcessingConfiguration.colorCurvesEnabled = value; - } - - /** - * Gets whether the color grading effect is enabled. - */ - public get cameraColorGradingEnabled(): boolean { - return this.imageProcessingConfiguration.colorGradingEnabled; - } - /** - * Gets whether the color grading effect is enabled. - */ - public set cameraColorGradingEnabled(value: boolean) { - this.imageProcessingConfiguration.colorGradingEnabled = value; - } - - /** - * Gets whether tonemapping is enabled or not. - */ - public get cameraToneMappingEnabled(): boolean { - return this._imageProcessingConfiguration.toneMappingEnabled; - } - /** - * Sets whether tonemapping is enabled or not - */ - public set cameraToneMappingEnabled(value: boolean) { - this._imageProcessingConfiguration.toneMappingEnabled = value; - } - - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public get cameraExposure(): number { - return this._imageProcessingConfiguration.exposure; - } - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public set cameraExposure(value: number) { - this._imageProcessingConfiguration.exposure = value; - } - - /** - * Gets The camera contrast used on this material. - */ - public get cameraContrast(): number { - return this._imageProcessingConfiguration.contrast; - } - - /** - * Sets The camera contrast used on this material. - */ - public set cameraContrast(value: number) { - this._imageProcessingConfiguration.contrast = value; - } - - /** - * Gets the Color Grading 2D Lookup Texture. - */ - public get cameraColorGradingTexture(): Nullable { - return this._imageProcessingConfiguration.colorGradingTexture; - } - /** - * Sets the Color Grading 2D Lookup Texture. - */ - public set cameraColorGradingTexture(value: Nullable) { - this._imageProcessingConfiguration.colorGradingTexture = value; - } - - /** - * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public get cameraColorCurves(): Nullable { - return this._imageProcessingConfiguration.colorCurves; - } - /** - * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public set cameraColorCurves(value: Nullable) { - this._imageProcessingConfiguration.colorCurves = value; - } - /** * Instantiates a new PBRMaterial instance. * diff --git a/packages/dev/core/src/Materials/imageProcessing.ts b/packages/dev/core/src/Materials/imageProcessing.ts new file mode 100644 index 00000000000..ab9d8f5da2d --- /dev/null +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -0,0 +1,197 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { serializeAsImageProcessingConfiguration } from "../Misc/decorators"; +import type { Nullable } from "../types"; +import type { ImageProcessingConfiguration } from "./imageProcessingConfiguration"; +import type { Observer } from "../Misc/observable"; +import type { BaseTexture } from "../Materials/Textures/baseTexture"; +import type { ColorCurves } from "../Materials/colorCurves"; + +// Explicit re-export of types to help TypeScript resolve them in declaration files +// export type { Observer } from "../Misc/observable"; +// export type { ColorCurves } from "./colorCurves"; + +type Constructor = new (...args: any[]) => T; + +/** + * Mixin to add Image processing defines to your material defines + * @internal + */ +export function ImageProcessingMixin(base: Tbase) { + return class extends base { + /** + * Constructor for the ImageProcessingMixin. + * @param args - arguments to pass to the base class constructor + */ + constructor(...args: any[]) { + super(...args); + // Decorators don't work on this annonymous class + // so I'm setting this up manually. + const fn = serializeAsImageProcessingConfiguration(); + fn.call(this, this, "_imageProcessingConfiguration"); + } + /** + * Default configuration related to image processing available in the standard Material. + */ + public _imageProcessingConfiguration: ImageProcessingConfiguration; + + /** + * Gets the image processing configuration used either in this material. + */ + public get imageProcessingConfiguration(): ImageProcessingConfiguration { + return this._imageProcessingConfiguration; + } + + /** + * Sets the Default image processing configuration used either in the this material. + * + * If sets to null, the scene one is in use. + */ + public set imageProcessingConfiguration(value: ImageProcessingConfiguration) { + this._attachImageProcessingConfiguration(value); + + // Ensure the effect will be rebuilt. + if ((this as any)._markAllSubMeshesAsImageProcessingDirty) { + (this as any)._markAllSubMeshesAsImageProcessingDirty(); + } + } + + /** + * Keep track of the image processing observer to allow dispose and replace. + */ + public _imageProcessingObserver: Nullable>; + + /** + * Attaches a new image processing configuration to the Standard Material. + * @param configuration + */ + public _attachImageProcessingConfiguration(configuration: Nullable): void { + if (configuration === this._imageProcessingConfiguration) { + return; + } + + // Detaches observer + if (this._imageProcessingConfiguration && this._imageProcessingObserver) { + this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); + } + + // Pick the scene configuration if needed + if (!configuration && (this as any).getScene) { + this._imageProcessingConfiguration = (this as any).getScene().imageProcessingConfiguration; + } else if (configuration) { + this._imageProcessingConfiguration = configuration; + } + + // Attaches observer + if (this._imageProcessingConfiguration) { + this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { + // Ensure the effect will be rebuilt. + if ((this as any)._markAllSubMeshesAsImageProcessingDirty) { + (this as any)._markAllSubMeshesAsImageProcessingDirty(); + } + }); + } + } + + /** + * Gets whether the color curves effect is enabled. + */ + public get cameraColorCurvesEnabled(): boolean { + return this.imageProcessingConfiguration.colorCurvesEnabled; + } + /** + * Sets whether the color curves effect is enabled. + */ + public set cameraColorCurvesEnabled(value: boolean) { + this.imageProcessingConfiguration.colorCurvesEnabled = value; + } + + /** + * Gets whether the color grading effect is enabled. + */ + public get cameraColorGradingEnabled(): boolean { + return this.imageProcessingConfiguration.colorGradingEnabled; + } + /** + * Gets whether the color grading effect is enabled. + */ + public set cameraColorGradingEnabled(value: boolean) { + this.imageProcessingConfiguration.colorGradingEnabled = value; + } + + /** + * Gets whether tonemapping is enabled or not. + */ + public get cameraToneMappingEnabled(): boolean { + return this._imageProcessingConfiguration.toneMappingEnabled; + } + /** + * Sets whether tonemapping is enabled or not + */ + public set cameraToneMappingEnabled(value: boolean) { + this._imageProcessingConfiguration.toneMappingEnabled = value; + } + + /** + * The camera exposure used on this material. + * This property is here and not in the camera to allow controlling exposure without full screen post process. + * This corresponds to a photographic exposure. + */ + public get cameraExposure(): number { + return this._imageProcessingConfiguration.exposure; + } + /** + * The camera exposure used on this material. + * This property is here and not in the camera to allow controlling exposure without full screen post process. + * This corresponds to a photographic exposure. + */ + public set cameraExposure(value: number) { + this._imageProcessingConfiguration.exposure = value; + } + + /** + * Gets The camera contrast used on this material. + */ + public get cameraContrast(): number { + return this._imageProcessingConfiguration.contrast; + } + + /** + * Sets The camera contrast used on this material. + */ + public set cameraContrast(value: number) { + this._imageProcessingConfiguration.contrast = value; + } + + /** + * Gets the Color Grading 2D Lookup Texture. + */ + public get cameraColorGradingTexture(): Nullable { + return this._imageProcessingConfiguration.colorGradingTexture; + } + /** + * Sets the Color Grading 2D Lookup Texture. + */ + public set cameraColorGradingTexture(value: Nullable) { + this._imageProcessingConfiguration.colorGradingTexture = value; + } + + /** + * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). + * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. + * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; + * corresponding to low luminance, medium luminance, and high luminance areas respectively. + */ + public get cameraColorCurves(): Nullable { + return this._imageProcessingConfiguration.colorCurves; + } + /** + * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). + * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. + * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; + * corresponding to low luminance, medium luminance, and high luminance areas respectively. + */ + public set cameraColorCurves(value: Nullable) { + this._imageProcessingConfiguration.colorCurves = value; + } + }; +} diff --git a/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts b/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts index 53f897fbdc2..de659b50f28 100644 --- a/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts +++ b/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts @@ -22,6 +22,36 @@ export interface IImageProcessingConfigurationDefines { SKIPFINALCOLORCLAMP: boolean; } +type Constructor = new (...args: any[]) => T; + +/** + * Mixin to add Image processing defines to your material defines + * @internal + */ +export function ImageProcessingDefinesMixin(base: Tbase) { + return class extends base implements IImageProcessingConfigurationDefines { + // Implement all members of IImageProcessingConfigurationDefines here + public IMAGEPROCESSING = false; + public VIGNETTE = false; + public VIGNETTEBLENDMODEMULTIPLY = false; + public VIGNETTEBLENDMODEOPAQUE = false; + public TONEMAPPING = 0; + public CONTRAST = false; + public COLORCURVES = false; + public COLORGRADING = false; + public COLORGRADING3D = false; + public SAMPLER3DGREENDEPTH = false; + public SAMPLER3DBGRMAP = false; + public DITHER = false; + public IMAGEPROCESSINGPOSTPROCESS = false; + public SKIPFINALCOLORCLAMP = false; + public EXPOSURE = false; + public MULTIVIEW = false; + public ORDER_INDEPENDENT_TRANSPARENCY = false; + public ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false; + }; +} + /** * @internal */ diff --git a/packages/dev/core/src/Materials/index.ts b/packages/dev/core/src/Materials/index.ts index 5aa74929c47..9c870151530 100644 --- a/packages/dev/core/src/Materials/index.ts +++ b/packages/dev/core/src/Materials/index.ts @@ -5,6 +5,7 @@ export * from "./iEffectFallbacks"; export * from "./effectFallbacks"; export * from "./effect"; export * from "./fresnelParameters"; +export * from "./imageProcessing"; export * from "./imageProcessingConfiguration"; export * from "./material"; export * from "./materialDefines"; @@ -39,6 +40,7 @@ export * from "./meshDebugPluginMaterial"; export * from "./GaussianSplatting/gaussianSplattingMaterial"; export * from "./materialHelper.functions"; export * from "./materialHelper.geometryrendering"; +export * from "./uv.defines"; import "./material.decalMap"; // async-loaded shaders diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index ff19a590ac4..d01e6f73c41 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -18,7 +18,10 @@ import type { AbstractEngine } from "../Engines/abstractEngine"; import type { Material } from "./material"; import type { Nullable } from "../types"; import { PrepareDefinesForClipPlanes } from "./clipPlaneMaterialHelper"; -import type { MorphTargetManager } from "core/Morph/morphTargetManager"; +import type { MorphTargetManager } from "../Morph/morphTargetManager"; +import { MaterialFlags } from "./materialFlags"; +import { Texture } from "./Textures/texture"; +import type { CubeTexture } from "./Textures/cubeTexture"; // Temps const TempFogColor = Color3.Black(); @@ -266,6 +269,123 @@ export function BindSceneUniformBuffer(effect: Effect, sceneUbo: UniformBuffer): sceneUbo.bindToEffect(effect, "Scene"); } +/** + * Update parameters for IBL + * @param scene The scene + * @param defines The list of shader defines for the material + * @param ubo The uniform buffer to update + * @param reflectionTexture The IBL texture + * @param realTimeFiltering Whether realtime filtering of IBL texture is being used + * @param supportTextureInfo Whether the texture info is supported + * @param supportLocalProjection Whether local projection is supported + * @param usePBR Whether PBR is being used + * @param supportSH Whether spherical harmonics are supported + * @param useColor Whether to use the reflection color + * @param reflectionColor The color to use for the reflection + */ +export function BindIBLParameters( + scene: Scene, + defines: any, + ubo: UniformBuffer, + reflectionTexture: Nullable = null, + realTimeFiltering: boolean = false, + supportTextureInfo: boolean = false, + supportLocalProjection: boolean = false, + usePBR: boolean = false, + supportSH: boolean = false, + useColor: boolean = false, + reflectionColor: Color3 = Color3.White() +): void { + if (scene.texturesEnabled) { + if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { + ubo.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix()); + ubo.updateFloat2("vReflectionInfos", reflectionTexture.level * scene.iblIntensity, 0); + + if (supportLocalProjection && (reflectionTexture).boundingBoxSize) { + const cubeTexture = reflectionTexture; + + ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition); + ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize); + } + + if (realTimeFiltering) { + const width = reflectionTexture.getSize().width; + ubo.updateFloat2("vReflectionFilteringInfo", width, Math.log2(width)); + } + + if (supportSH && !defines.USEIRRADIANCEMAP) { + const polynomials = reflectionTexture.sphericalPolynomial; + if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) { + if (defines.SPHERICAL_HARMONICS) { + const preScaledHarmonics = polynomials.preScaledHarmonics; + ubo.updateVector3("vSphericalL00", preScaledHarmonics.l00); + ubo.updateVector3("vSphericalL1_1", preScaledHarmonics.l1_1); + ubo.updateVector3("vSphericalL10", preScaledHarmonics.l10); + ubo.updateVector3("vSphericalL11", preScaledHarmonics.l11); + ubo.updateVector3("vSphericalL2_2", preScaledHarmonics.l2_2); + ubo.updateVector3("vSphericalL2_1", preScaledHarmonics.l2_1); + ubo.updateVector3("vSphericalL20", preScaledHarmonics.l20); + ubo.updateVector3("vSphericalL21", preScaledHarmonics.l21); + ubo.updateVector3("vSphericalL22", preScaledHarmonics.l22); + } else { + ubo.updateFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z); + ubo.updateFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z); + ubo.updateFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z); + ubo.updateFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x, polynomials.xx.y - polynomials.zz.y, polynomials.xx.z - polynomials.zz.z); + ubo.updateFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x, polynomials.yy.y - polynomials.zz.y, polynomials.yy.z - polynomials.zz.z); + ubo.updateFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z); + ubo.updateFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z); + ubo.updateFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z); + ubo.updateFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z); + } + } + } else if (usePBR) { + // If we're using an irradiance map with a dominant direction assigned, set it. + if (defines.USEIRRADIANCEMAP && defines.USE_IRRADIANCE_DOMINANT_DIRECTION) { + ubo.updateVector3("vReflectionDominantDirection", reflectionTexture.irradianceTexture!._dominantDirection!); + } + } + + if (supportTextureInfo) { + ubo.updateFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset); + } + } + } + if (useColor) { + ubo.updateColor3("vReflectionColor", reflectionColor); + } +} + +/** + * Update parameters for IBL + * @param scene The scene + * @param defines The list of shader defines for the material + * @param ubo The uniform buffer to update + * @param reflectionTexture The IBL texture + * @param realTimeFiltering Whether realtime filtering of IBL texture is being used + */ +export function BindIBLSamplers(scene: Scene, defines: any, ubo: UniformBuffer, reflectionTexture: Nullable = null, realTimeFiltering: boolean = false): void { + if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { + if (defines.LODBASEDMICROSFURACE) { + ubo.setTexture("reflectionSampler", reflectionTexture); + } else { + ubo.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture); + ubo.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture); + ubo.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture); + } + + if (defines.USEIRRADIANCEMAP) { + ubo.setTexture("irradianceSampler", reflectionTexture.irradianceTexture); + } + + //if realtime filtering and using CDF maps, set them. + const cdfGenerator = scene.iblCdfGenerator; + if (realTimeFiltering && cdfGenerator) { + ubo.setTexture("icdfSampler", cdfGenerator.getIcdfTexture()); + } + } +} + /** * Helps preparing the defines values about the UVs in used in the effect. * UVs are shared as much as we can across channels in the shaders. @@ -602,6 +722,139 @@ export function PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, define return state.needNormals; } +/** + * Prepare defines relating to IBL logic. + * @param scene The scene + * @param reflectionTexture The texture to use for IBL + * @param defines The defines to update + * @param realTimeFiltering Whether realtime filting of IBL texture is being used + * @param realTimeFilteringQuality The quality of realtime filtering + * @param forceSHInVertex Whether the SH are handled in the vertex shader + */ +export function PrepareDefinesForIBL( + scene: Scene, + reflectionTexture: Nullable, + defines: any, + realTimeFiltering: boolean = false, + realTimeFilteringQuality: number = Constants.TEXTURE_FILTERING_QUALITY_LOW, + forceSHInVertex: boolean = false +) { + if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { + if (!reflectionTexture.isReadyOrNotBlocking()) { + return; + } + defines.REFLECTION = true; + defines.GAMMAREFLECTION = reflectionTexture.gammaSpace; + defines.RGBDREFLECTION = reflectionTexture.isRGBD; + defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha; + defines.LINEARSPECULARREFLECTION = reflectionTexture.linearSpecularLOD; + defines.USEIRRADIANCEMAP = false; + + const engine = scene.getEngine(); + if (realTimeFiltering && realTimeFilteringQuality > 0) { + defines.NUM_SAMPLES = "" + realTimeFilteringQuality; + if (engine._features.needTypeSuffixInShaderConstants) { + defines.NUM_SAMPLES = defines.NUM_SAMPLES + "u"; + } + + defines.REALTIME_FILTERING = true; + if (scene.iblCdfGenerator) { + defines.IBL_CDF_FILTERING = true; + } + } else { + defines.REALTIME_FILTERING = false; + } + + defines.INVERTCUBICMAP = reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE; + defines.REFLECTIONMAP_3D = reflectionTexture.isCube; + defines.REFLECTIONMAP_OPPOSITEZ = defines.REFLECTIONMAP_3D && scene.useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ; + + defines.REFLECTIONMAP_CUBIC = false; + defines.REFLECTIONMAP_EXPLICIT = false; + defines.REFLECTIONMAP_PLANAR = false; + defines.REFLECTIONMAP_PROJECTION = false; + defines.REFLECTIONMAP_SKYBOX = false; + defines.REFLECTIONMAP_SPHERICAL = false; + defines.REFLECTIONMAP_EQUIRECTANGULAR = false; + defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; + defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; + + switch (reflectionTexture.coordinatesMode) { + case Texture.EXPLICIT_MODE: + defines.REFLECTIONMAP_EXPLICIT = true; + break; + case Texture.PLANAR_MODE: + defines.REFLECTIONMAP_PLANAR = true; + break; + case Texture.PROJECTION_MODE: + defines.REFLECTIONMAP_PROJECTION = true; + break; + case Texture.SKYBOX_MODE: + defines.REFLECTIONMAP_SKYBOX = true; + break; + case Texture.SPHERICAL_MODE: + defines.REFLECTIONMAP_SPHERICAL = true; + break; + case Texture.EQUIRECTANGULAR_MODE: + defines.REFLECTIONMAP_EQUIRECTANGULAR = true; + break; + case Texture.FIXED_EQUIRECTANGULAR_MODE: + defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true; + break; + case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE: + defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true; + break; + case Texture.CUBIC_MODE: + case Texture.INVCUBIC_MODE: + default: + defines.REFLECTIONMAP_CUBIC = true; + defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (reflectionTexture).boundingBoxSize ? true : false; + break; + } + + if (reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) { + if (reflectionTexture.irradianceTexture) { + defines.USEIRRADIANCEMAP = true; + defines.USESPHERICALFROMREFLECTIONMAP = false; + defines.USESPHERICALINVERTEX = false; + if (reflectionTexture.irradianceTexture._dominantDirection) { + defines.USE_IRRADIANCE_DOMINANT_DIRECTION = true; + } + } + // Assume using spherical polynomial if the reflection texture is a cube map + else if (reflectionTexture.isCube) { + defines.USESPHERICALFROMREFLECTIONMAP = true; + defines.USEIRRADIANCEMAP = false; + defines.USE_IRRADIANCE_DOMINANT_DIRECTION = false; + defines.USESPHERICALINVERTEX = forceSHInVertex; + } + } + } else { + defines.REFLECTION = false; + defines.REFLECTIONMAP_3D = false; + defines.REFLECTIONMAP_SPHERICAL = false; + defines.REFLECTIONMAP_PLANAR = false; + defines.REFLECTIONMAP_CUBIC = false; + defines.USE_LOCAL_REFLECTIONMAP_CUBIC = false; + defines.REFLECTIONMAP_PROJECTION = false; + defines.REFLECTIONMAP_SKYBOX = false; + defines.REFLECTIONMAP_EXPLICIT = false; + defines.REFLECTIONMAP_EQUIRECTANGULAR = false; + defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; + defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; + defines.INVERTCUBICMAP = false; + defines.USESPHERICALFROMREFLECTIONMAP = false; + defines.USEIRRADIANCEMAP = false; + defines.USE_IRRADIANCE_DOMINANT_DIRECTION = false; + defines.USESPHERICALINVERTEX = false; + defines.REFLECTIONMAP_OPPOSITEZ = false; + defines.LODINREFLECTIONALPHA = false; + defines.GAMMAREFLECTION = false; + defines.RGBDREFLECTION = false; + defines.LINEARSPECULARREFLECTION = false; + } +} + /** * Prepares the defines related to the light information passed in parameter * @param scene The scene we are intending to draw @@ -1126,6 +1379,51 @@ export function PrepareUniformsAndSamplersForLight( } } +/** + * Append uniforms and samplers related to IBL to the provided lists + * @param uniformsList The list of uniforms to append to + * @param samplersList The list of samplers to append to + * @param useSH Whether to include spherical harmonics uniforms + */ +export function PrepareUniformsAndSamplersForIBL(uniformsList: string[], samplersList: string[], useSH: boolean): void { + const iblUniforms = [ + "vReflectionMicrosurfaceInfos", + "vReflectionDominantDirection", + "reflectionMatrix", + "vReflectionInfos", + "vReflectionPosition", + "vReflectionSize", + "vReflectionColor", + "vReflectionFilteringInfo", + ]; + if (useSH) { + iblUniforms.push( + "vSphericalX", + "vSphericalY", + "vSphericalZ", + "vSphericalXX_ZZ", + "vSphericalYY_ZZ", + "vSphericalZZ", + "vSphericalXY", + "vSphericalYZ", + "vSphericalZX", + "vSphericalL00", + "vSphericalL1_1", + "vSphericalL10", + "vSphericalL11", + "vSphericalL2_2", + "vSphericalL2_1", + "vSphericalL20", + "vSphericalL21", + "vSphericalL22" + ); + } + uniformsList.push(...iblUniforms); + + const iblSamplers = ["reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh", "irradianceSampler", "icdfSampler"]; + samplersList.push(...iblSamplers); +} + /** * Prepares the uniforms and samplers list to be used in the effect * @param uniformsListOrOptions The uniform names to prepare or an EffectCreationOptions containing the list and extra information @@ -1178,3 +1476,63 @@ export function PrepareUniformsAndSamplersList(uniformsListOrOptions: string[] | samplersList.push("bakedVertexAnimationTexture"); } } + +/** + * + * @param ubo Add uniforms to UBO + * @param supportTextureInfo Add uniforms for texture info if true + * @param supportLocalProjection Add uniforms for local projection if true + * @param usePBR Add uniforms for IBL if true + * @param supportSH Add uniforms for spherical harmonics if true + * @param useColor Add uniforms for reflection color if true + */ +export function PrepareUniformLayoutForIBL( + ubo: UniformBuffer, + supportTextureInfo: boolean = false, + supportLocalProjection: boolean = false, + usePBR: boolean = false, + supportSH: boolean = false, + useColor: boolean = false +): void { + ubo.addUniform("vReflectionInfos", 2); + ubo.addUniform("reflectionMatrix", 16); + if (supportTextureInfo) { + ubo.addUniform("vReflectionMicrosurfaceInfos", 3); + } + + if (supportLocalProjection) { + ubo.addUniform("vReflectionPosition", 3); + ubo.addUniform("vReflectionSize", 3); + } + + if (usePBR) { + ubo.addUniform("vReflectionFilteringInfo", 2); + ubo.addUniform("vReflectionDominantDirection", 3); + } + + if (useColor) { + ubo.addUniform("vReflectionColor", 3); + } + + if (supportSH) { + ubo.addUniform("vSphericalL00", 3); + ubo.addUniform("vSphericalL1_1", 3); + ubo.addUniform("vSphericalL10", 3); + ubo.addUniform("vSphericalL11", 3); + ubo.addUniform("vSphericalL2_2", 3); + ubo.addUniform("vSphericalL2_1", 3); + ubo.addUniform("vSphericalL20", 3); + ubo.addUniform("vSphericalL21", 3); + ubo.addUniform("vSphericalL22", 3); + + ubo.addUniform("vSphericalX", 3); + ubo.addUniform("vSphericalY", 3); + ubo.addUniform("vSphericalZ", 3); + ubo.addUniform("vSphericalXX_ZZ", 3); + ubo.addUniform("vSphericalYY_ZZ", 3); + ubo.addUniform("vSphericalZZ", 3); + ubo.addUniform("vSphericalXY", 3); + ubo.addUniform("vSphericalYZ", 3); + ubo.addUniform("vSphericalZX", 3); + } +} diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index ccc8f1d952d..48045debfa0 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { serialize, serializeAsColor3, expandToProperty, serializeAsFresnelParameters, serializeAsTexture } from "../Misc/decorators"; -import type { Observer } from "../Misc/observable"; import { SmartArray } from "../Misc/smartArray"; import type { IAnimatable } from "../Animations/animatable.interface"; @@ -14,9 +13,8 @@ import type { AbstractMesh } from "../Meshes/abstractMesh"; import type { Mesh } from "../Meshes/mesh"; import { PrePassConfiguration } from "./prePassConfiguration"; -import type { IImageProcessingConfigurationDefines } from "./imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "./imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "./imageProcessingConfiguration"; -import type { ColorCurves } from "./colorCurves"; import type { FresnelParameters } from "./fresnelParameters"; import type { ICustomShaderNameResolveOptions } from "../Materials/material"; import { Material } from "../Materials/material"; @@ -25,7 +23,6 @@ import { MaterialDefines } from "../Materials/materialDefines"; import { PushMaterial } from "./pushMaterial"; import type { BaseTexture } from "../Materials/Textures/baseTexture"; -import { Texture } from "../Materials/Textures/texture"; import type { CubeTexture } from "../Materials/Textures/cubeTexture"; import type { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture"; import { RegisterClass } from "../Misc/typeStore"; @@ -43,6 +40,7 @@ import { BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, + BindIBLParameters, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, @@ -51,27 +49,28 @@ import { PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, + PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, + PrepareUniformsAndSamplersForIBL, PrepareUniformsAndSamplersList, + PrepareUniformLayoutForIBL, } from "./materialHelper.functions"; import { SerializationHelper } from "../Misc/decorators.serialization"; import { ShaderLanguage } from "./shaderLanguage"; import { MaterialHelperGeometryRendering } from "./materialHelper.geometryrendering"; +import { UVDefinesMixin } from "./uv.defines"; +import { ImageProcessingMixin } from "./imageProcessing"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; +class StandardMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} + /** @internal */ -export class StandardMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { - public MAINUV1 = false; - public MAINUV2 = false; - public MAINUV3 = false; - public MAINUV4 = false; - public MAINUV5 = false; - public MAINUV6 = false; +export class StandardMaterialDefines extends ImageProcessingDefinesMixin(StandardMaterialDefinesBase) { public DIFFUSE = false; public DIFFUSEDIRECTUV = 0; public BAKED_VERTEX_ANIMATION_TEXTURE = false; @@ -111,12 +110,6 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr public FRESNEL = false; public NORMAL = false; public TANGENT = false; - public UV1 = false; - public UV2 = false; - public UV3 = false; - public UV4 = false; - public UV5 = false; - public UV6 = false; public VERTEXCOLOR = false; public VERTEXALPHA = false; public NUM_BONE_INFLUENCERS = 0; @@ -211,23 +204,6 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr public RGBDREFLECTION = false; public RGBDREFRACTION = false; - public IMAGEPROCESSING = false; - public VIGNETTE = false; - public VIGNETTEBLENDMODEMULTIPLY = false; - public VIGNETTEBLENDMODEOPAQUE = false; - public TONEMAPPING = 0; - public CONTRAST = false; - public COLORCURVES = false; - public COLORGRADING = false; - public COLORGRADING3D = false; - public SAMPLER3DGREENDEPTH = false; - public SAMPLER3DBGRMAP = false; - public DITHER = false; - public IMAGEPROCESSINGPOSTPROCESS = false; - public SKIPFINALCOLORCLAMP = false; - public MULTIVIEW = false; - public ORDER_INDEPENDENT_TRANSPARENCY = false; - public ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false; public CAMERA_ORTHOGRAPHIC = false; public CAMERA_PERSPECTIVE = false; public AREALIGHTSUPPORTED = true; @@ -242,7 +218,6 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr * @internal */ public IS_REFRACTION_LINEAR = false; - public EXPOSURE = false; public DECAL_AFTER_DETAIL = false; @@ -254,33 +229,15 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr super(externalProperties); this.rebuild(); } - - public setReflectionMode(modeToEnable: string) { - const modes = [ - "REFLECTIONMAP_CUBIC", - "REFLECTIONMAP_EXPLICIT", - "REFLECTIONMAP_PLANAR", - "REFLECTIONMAP_PROJECTION", - "REFLECTIONMAP_PROJECTION", - "REFLECTIONMAP_SKYBOX", - "REFLECTIONMAP_SPHERICAL", - "REFLECTIONMAP_EQUIRECTANGULAR", - "REFLECTIONMAP_EQUIRECTANGULAR_FIXED", - "REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED", - ]; - - for (const mode of modes) { - (this)[mode] = mode === modeToEnable; - } - } } +class StandardMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * This is the default material used in Babylon. It is the best trade off between quality * and performances. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/materials_introduction */ -export class StandardMaterial extends PushMaterial { +export class StandardMaterial extends StandardMaterialBase { /** * Force all the standard materials to compile to glsl even on WebGPU engines. * False by default. This is mostly meant for backward compatibility. @@ -627,64 +584,6 @@ export class StandardMaterial extends PushMaterial { @expandToProperty("_markAllSubMeshesAsMiscDirty") public applyDecalMapAfterDetailMap: boolean; - /** - * Default configuration related to image processing available in the standard Material. - */ - protected _imageProcessingConfiguration: ImageProcessingConfiguration; - - /** - * Gets the image processing configuration used either in this material. - */ - public get imageProcessingConfiguration(): ImageProcessingConfiguration { - return this._imageProcessingConfiguration; - } - - /** - * Sets the Default image processing configuration used either in the this material. - * - * If sets to null, the scene one is in use. - */ - public set imageProcessingConfiguration(value: ImageProcessingConfiguration) { - this._attachImageProcessingConfiguration(value); - - // Ensure the effect will be rebuilt. - this._markAllSubMeshesAsImageProcessingDirty(); - } - - /** - * Keep track of the image processing observer to allow dispose and replace. - */ - private _imageProcessingObserver: Nullable>; - - /** - * Attaches a new image processing configuration to the Standard Material. - * @param configuration - */ - protected _attachImageProcessingConfiguration(configuration: Nullable): void { - if (configuration === this._imageProcessingConfiguration) { - return; - } - - // Detaches observer - if (this._imageProcessingConfiguration && this._imageProcessingObserver) { - this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); - } - - // Pick the scene configuration if needed - if (!configuration) { - this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration; - } else { - this._imageProcessingConfiguration = configuration; - } - - // Attaches observer - if (this._imageProcessingConfiguration) { - this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { - this._markAllSubMeshesAsImageProcessingDirty(); - }); - } - } - private _shadersLoaded = false; /** @@ -699,108 +598,6 @@ export class StandardMaterial extends PushMaterial { return !this.disableDepthWrite; } - /** - * Gets whether the color curves effect is enabled. - */ - public get cameraColorCurvesEnabled(): boolean { - return this.imageProcessingConfiguration.colorCurvesEnabled; - } - /** - * Sets whether the color curves effect is enabled. - */ - public set cameraColorCurvesEnabled(value: boolean) { - this.imageProcessingConfiguration.colorCurvesEnabled = value; - } - - /** - * Gets whether the color grading effect is enabled. - */ - public get cameraColorGradingEnabled(): boolean { - return this.imageProcessingConfiguration.colorGradingEnabled; - } - /** - * Gets whether the color grading effect is enabled. - */ - public set cameraColorGradingEnabled(value: boolean) { - this.imageProcessingConfiguration.colorGradingEnabled = value; - } - - /** - * Gets whether tonemapping is enabled or not. - */ - public get cameraToneMappingEnabled(): boolean { - return this._imageProcessingConfiguration.toneMappingEnabled; - } - /** - * Sets whether tonemapping is enabled or not - */ - public set cameraToneMappingEnabled(value: boolean) { - this._imageProcessingConfiguration.toneMappingEnabled = value; - } - - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public get cameraExposure(): number { - return this._imageProcessingConfiguration.exposure; - } - /** - * The camera exposure used on this material. - * This property is here and not in the camera to allow controlling exposure without full screen post process. - * This corresponds to a photographic exposure. - */ - public set cameraExposure(value: number) { - this._imageProcessingConfiguration.exposure = value; - } - - /** - * Gets The camera contrast used on this material. - */ - public get cameraContrast(): number { - return this._imageProcessingConfiguration.contrast; - } - - /** - * Sets The camera contrast used on this material. - */ - public set cameraContrast(value: number) { - this._imageProcessingConfiguration.contrast = value; - } - - /** - * Gets the Color Grading 2D Lookup Texture. - */ - public get cameraColorGradingTexture(): Nullable { - return this._imageProcessingConfiguration.colorGradingTexture; - } - /** - * Sets the Color Grading 2D Lookup Texture. - */ - public set cameraColorGradingTexture(value: Nullable) { - this._imageProcessingConfiguration.colorGradingTexture = value; - } - - /** - * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public get cameraColorCurves(): Nullable { - return this._imageProcessingConfiguration.colorCurves; - } - /** - * The color grading curves provide additional color adjustment that is applied after any color grading transform (3D LUT). - * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. - * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; - * corresponding to low luminance, medium luminance, and high luminance areas respectively. - */ - public set cameraColorCurves(value: Nullable) { - this._imageProcessingConfiguration.colorCurves = value; - } - /** * Can this material render to several textures at once */ @@ -1029,60 +826,9 @@ export class StandardMaterial extends PushMaterial { } else { defines.OPACITY = false; } - - if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) { - if (!this._reflectionTexture.isReadyOrNotBlocking()) { - return false; - } else { - defines._needNormals = true; - defines.REFLECTION = true; - - defines.ROUGHNESS = this._roughness > 0; - defines.REFLECTIONOVERALPHA = this._useReflectionOverAlpha; - defines.INVERTCUBICMAP = this._reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE; - defines.REFLECTIONMAP_3D = this._reflectionTexture.isCube; - defines.REFLECTIONMAP_OPPOSITEZ = - defines.REFLECTIONMAP_3D && this.getScene().useRightHandedSystem ? !this._reflectionTexture.invertZ : this._reflectionTexture.invertZ; - defines.RGBDREFLECTION = this._reflectionTexture.isRGBD; - - switch (this._reflectionTexture.coordinatesMode) { - case Texture.EXPLICIT_MODE: - defines.setReflectionMode("REFLECTIONMAP_EXPLICIT"); - break; - case Texture.PLANAR_MODE: - defines.setReflectionMode("REFLECTIONMAP_PLANAR"); - break; - case Texture.PROJECTION_MODE: - defines.setReflectionMode("REFLECTIONMAP_PROJECTION"); - break; - case Texture.SKYBOX_MODE: - defines.setReflectionMode("REFLECTIONMAP_SKYBOX"); - break; - case Texture.SPHERICAL_MODE: - defines.setReflectionMode("REFLECTIONMAP_SPHERICAL"); - break; - case Texture.EQUIRECTANGULAR_MODE: - defines.setReflectionMode("REFLECTIONMAP_EQUIRECTANGULAR"); - break; - case Texture.FIXED_EQUIRECTANGULAR_MODE: - defines.setReflectionMode("REFLECTIONMAP_EQUIRECTANGULAR_FIXED"); - break; - case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE: - defines.setReflectionMode("REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED"); - break; - case Texture.CUBIC_MODE: - case Texture.INVCUBIC_MODE: - default: - defines.setReflectionMode("REFLECTIONMAP_CUBIC"); - break; - } - - defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (this._reflectionTexture).boundingBoxSize ? true : false; - } - } else { - defines.REFLECTION = false; - defines.REFLECTIONMAP_OPPOSITEZ = false; - } + defines.ROUGHNESS = this._roughness > 0; + defines.REFLECTIONOVERALPHA = this._useReflectionOverAlpha; + PrepareDefinesForIBL(scene, this._reflectionTexture, defines); if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { if (!this._emissiveTexture.isReadyOrNotBlocking()) { @@ -1388,7 +1134,6 @@ export class StandardMaterial extends PushMaterial { "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", - "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", @@ -1398,7 +1143,6 @@ export class StandardMaterial extends PushMaterial { "diffuseMatrix", "ambientMatrix", "opacityMatrix", - "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", @@ -1414,8 +1158,6 @@ export class StandardMaterial extends PushMaterial { "emissiveRightColor", "refractionLeftColor", "refractionRightColor", - "vReflectionPosition", - "vReflectionSize", "vRefractionPosition", "vRefractionSize", "logarithmicDepthConstant", @@ -1447,6 +1189,7 @@ export class StandardMaterial extends PushMaterial { "areaLightsLTC2Sampler", ]; + PrepareUniformsAndSamplersForIBL(uniforms, samplers, false); const uniformBuffers = ["Material", "Scene", "Mesh"]; const indexParameters = { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }; @@ -1583,9 +1326,6 @@ export class StandardMaterial extends PushMaterial { ubo.addUniform("vDiffuseInfos", 2); ubo.addUniform("vAmbientInfos", 2); ubo.addUniform("vOpacityInfos", 2); - ubo.addUniform("vReflectionInfos", 2); - ubo.addUniform("vReflectionPosition", 3); - ubo.addUniform("vReflectionSize", 3); ubo.addUniform("vEmissiveInfos", 2); ubo.addUniform("vLightmapInfos", 2); ubo.addUniform("vSpecularInfos", 2); @@ -1594,7 +1334,6 @@ export class StandardMaterial extends PushMaterial { ubo.addUniform("diffuseMatrix", 16); ubo.addUniform("ambientMatrix", 16); ubo.addUniform("opacityMatrix", 16); - ubo.addUniform("reflectionMatrix", 16); ubo.addUniform("emissiveMatrix", 16); ubo.addUniform("lightmapMatrix", 16); ubo.addUniform("specularMatrix", 16); @@ -1612,6 +1351,8 @@ export class StandardMaterial extends PushMaterial { ubo.addUniform("vAmbientColor", 3); ubo.addUniform("cameraInfo", 4); + PrepareUniformLayoutForIBL(ubo, false, true); + super.buildUniformLayout(); } @@ -1726,19 +1467,7 @@ export class StandardMaterial extends PushMaterial { ubo.updateFloat("alphaCutOff", this.alphaCutOff); } - if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) { - ubo.updateFloat2("vReflectionInfos", this._reflectionTexture.level, this.roughness); - ubo.updateMatrix("reflectionMatrix", this._reflectionTexture.getReflectionTextureMatrix()); - - if ((this._reflectionTexture).boundingBoxSize) { - const cubeTexture = this._reflectionTexture; - - ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition); - ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize); - } - } else { - ubo.updateFloat2("vReflectionInfos", 0.0, this.roughness); - } + BindIBLParameters(scene, defines, ubo, this._reflectionTexture, false, true, true); if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); diff --git a/packages/dev/core/src/Materials/uv.defines.ts b/packages/dev/core/src/Materials/uv.defines.ts new file mode 100644 index 00000000000..12eec96845c --- /dev/null +++ b/packages/dev/core/src/Materials/uv.defines.ts @@ -0,0 +1,22 @@ +type Constructor = new (...args: any[]) => T; + +/** + * Mixin to add UV defines to your material defines + * @internal + */ +export function UVDefinesMixin(base: Tbase) { + return class extends base { + public MAINUV1 = false; + public MAINUV2 = false; + public MAINUV3 = false; + public MAINUV4 = false; + public MAINUV5 = false; + public MAINUV6 = false; + public UV1 = false; + public UV2 = false; + public UV3 = false; + public UV4 = false; + public UV5 = false; + public UV6 = false; + }; +} diff --git a/packages/dev/core/src/Misc/decorators.ts b/packages/dev/core/src/Misc/decorators.ts index 9e07eb69699..3abc2bb90cb 100644 --- a/packages/dev/core/src/Misc/decorators.ts +++ b/packages/dev/core/src/Misc/decorators.ts @@ -158,3 +158,33 @@ nativeOverride.filter = function boolean>(predica return (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<(...params: Parameters) => unknown>) => nativeOverride(target, propertyKey, descriptor, predicate); }; + +export function addAccessorsForMaterialProperty(setCallback: string, targetKey: Nullable = null) { + return (target: any, propertyKey: string) => { + const key = propertyKey; + const newKey = targetKey || ""; + Object.defineProperty(target, newKey, { + get: function (this: any) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return this[key].value; + }, + set: function (this: any, value) { + // does this object (i.e. vector3) has an equals function? use it! + // Note - not using "with epsilon" here, it is expected te behave like the internal cache does. + if (typeof this[key]?.value?.equals === "function") { + if (this[key].value.equals(value)) { + return; + } + } + if (this[key].value === value) { + return; + } + this[key].value = value; + + target[setCallback].apply(this); + }, + enumerable: true, + configurable: true, + }); + }; +} diff --git a/packages/dev/core/src/Particles/baseParticleSystem.ts b/packages/dev/core/src/Particles/baseParticleSystem.ts index 4d082cd9520..dc628b486b7 100644 --- a/packages/dev/core/src/Particles/baseParticleSystem.ts +++ b/packages/dev/core/src/Particles/baseParticleSystem.ts @@ -1,7 +1,6 @@ import type { Nullable } from "../types"; import { Vector2, Vector3 } from "../Maths/math.vector"; import type { AbstractMesh } from "../Meshes/abstractMesh"; -import type { ImageProcessingConfiguration } from "../Materials/imageProcessingConfiguration"; import { ImageProcessingConfigurationDefines } from "../Materials/imageProcessingConfiguration.defines"; import type { ColorGradient, FactorGradient, Color3Gradient, IValueGradient } from "../Misc/gradients"; import type { BoxParticleEmitter } from "../Particles/EmitterTypes/boxParticleEmitter"; @@ -24,14 +23,16 @@ import type { SphereDirectedParticleEmitter, SphereParticleEmitter } from "./Emi import type { CylinderDirectedParticleEmitter, CylinderParticleEmitter } from "./EmitterTypes/cylinderParticleEmitter"; import type { ConeDirectedParticleEmitter, ConeParticleEmitter } from "./EmitterTypes/coneParticleEmitter"; import { RegisterClass } from "../Misc/typeStore"; +import { ImageProcessingMixin } from "core/Materials/imageProcessing"; +class BaseParticleSystemBase extends ImageProcessingMixin(Object) {} /** * This represents the base class for particle system in Babylon. * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust. * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function. * @example https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro */ -export class BaseParticleSystem implements IClipPlanesHolder { +export class BaseParticleSystem extends BaseParticleSystemBase implements IClipPlanesHolder { /** * Source color is added to the destination color without alpha affecting the result. Great for additive glow effects (fire, magic, lasers) */ @@ -739,44 +740,6 @@ export class BaseParticleSystem implements IClipPlanesHolder { */ protected _imageProcessingConfigurationDefines = new ImageProcessingConfigurationDefines(); - /** - * Default configuration related to image processing available in the standard Material. - */ - protected _imageProcessingConfiguration: Nullable; - - /** - * Gets the image processing configuration used either in this material. - */ - public get imageProcessingConfiguration(): Nullable { - return this._imageProcessingConfiguration; - } - - /** - * Sets the Default image processing configuration used either in the this material. - * - * If sets to null, the scene one is in use. - */ - public set imageProcessingConfiguration(value: Nullable) { - this._attachImageProcessingConfiguration(value); - } - - /** - * Attaches a new image processing configuration to the Standard Material. - * @param configuration - */ - protected _attachImageProcessingConfiguration(configuration: Nullable): void { - if (configuration === this._imageProcessingConfiguration) { - return; - } - - // Pick the scene configuration if needed. - if (!configuration && this._scene) { - this._imageProcessingConfiguration = this._scene.imageProcessingConfiguration; - } else { - this._imageProcessingConfiguration = configuration; - } - } - /** @internal */ protected _reset() {} @@ -810,6 +773,7 @@ export class BaseParticleSystem implements IClipPlanesHolder { * @param name The name of the particle system */ public constructor(name: string) { + super(name); this.id = name; this.name = name; } diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts index 666d6a90324..409e699f3ae 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts @@ -10,6 +10,7 @@ import { expandToProperty, serialize } from "core/Misc/decorators"; import { RegisterClass } from "core/Misc/typeStore"; import { ShaderLanguage } from "core/Materials/shaderLanguage"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; /** * @internal */ @@ -72,7 +73,7 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { return true; } - constructor(material: Material | StandardMaterial | PBRBaseMaterial) { + constructor(material: Material | StandardMaterial | PBRBaseMaterial | OpenPBRMaterial) { super(material, IBLShadowsPluginMaterial.Name, 310, new MaterialIBLShadowsRenderDefines()); this._internalMarkAllSubMeshesAsTexturesDirty = material._dirtyCallbacks[Constants.MATERIAL_TextureDirtyFlag]; } @@ -160,6 +161,27 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #endif #endif `; + } else if (this._material instanceof OpenPBRMaterial) { + // eslint-disable-next-line @typescript-eslint/naming-convention + frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = ` + #ifdef RENDER_WITH_IBL_SHADOWS + #ifndef UNLIT + #ifdef REFLECTION + #ifdef COLORED_IBL_SHADOWS + var shadowValue: vec3f = computeIndirectShadow(); + finalIrradiance *= shadowValue; + finalRadianceScaled *= mix(vec3f(1.0), shadowValue, roughness); + #else + var shadowValue: vec2f = computeIndirectShadow(); + finalIrradiance *= vec3f(shadowValue.x); + finalRadianceScaled *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness)); + #endif + #endif + #else + finalDiffuse *= computeIndirectShadow().x; + #endif + #endif + `; } else { frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = ` #ifdef RENDER_WITH_IBL_SHADOWS @@ -217,6 +239,27 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #endif #endif `; + } else if (this._material instanceof OpenPBRMaterial) { + // eslint-disable-next-line @typescript-eslint/naming-convention + frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = ` + #ifdef RENDER_WITH_IBL_SHADOWS + #ifndef UNLIT + #ifdef REFLECTION + #ifdef COLORED_IBL_SHADOWS + vec3 shadowValue = computeIndirectShadow(); + finalIrradiance.rgb *= shadowValue.rgb; + finalRadianceScaled *= mix(vec3(1.0), shadowValue.rgb, roughness); + #else + vec2 shadowValue = computeIndirectShadow(); + finalIrradiance *= shadowValue.x; + finalRadianceScaled *= mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness); + #endif + #endif + #else + finalDiffuse *= computeIndirectShadow().x; + #endif + #endif + `; } else { frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = ` #ifdef RENDER_WITH_IBL_SHADOWS diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts index 010593f29a0..6eeb74c406c 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts @@ -27,6 +27,7 @@ import type { Material } from "core/Materials/material"; import { Observable } from "core/Misc/observable"; import "../geometryBufferRendererSceneComponent"; import "../iblCdfGeneratorSceneComponent"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; interface IIblShadowsSettings { /** @@ -1115,7 +1116,7 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { } protected _addShadowSupportToMaterial(material: Material) { - if (!(material instanceof PBRBaseMaterial) && !(material instanceof StandardMaterial)) { + if (!(material instanceof PBRBaseMaterial) && !(material instanceof StandardMaterial) && !(material instanceof OpenPBRMaterial)) { return; } let plugin = material.pluginManager?.getPlugin(IBLShadowsPluginMaterial.Name); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx index 549fcfa18e6..5a6f77003f3 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx @@ -5,10 +5,7 @@ uniform Material uniform vec4 vPrimaryColor; uniform vec4 vPrimaryColorShadow; uniform vec2 vDiffuseInfos; - uniform vec2 vReflectionInfos; uniform mat4 diffuseMatrix; - uniform mat4 reflectionMatrix; - uniform vec3 vReflectionMicrosurfaceInfos; uniform float fFovMultiplier; uniform float pointSize; @@ -17,6 +14,10 @@ uniform Material uniform vec3 vBackgroundCenter; uniform vec4 vReflectionControl; uniform vec2 projectedGroundInfos; + + uniform vec2 vReflectionInfos; + uniform mat4 reflectionMatrix; + uniform vec3 vReflectionMicrosurfaceInfos; }; #include diff --git a/packages/dev/core/src/Shaders/ShadersInclude/defaultUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/defaultUboDeclaration.fx index b68982042da..64a29678059 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/defaultUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/defaultUboDeclaration.fx @@ -14,9 +14,6 @@ uniform Material vec2 vDiffuseInfos; vec2 vAmbientInfos; vec2 vOpacityInfos; - vec2 vReflectionInfos; - vec3 vReflectionPosition; - vec3 vReflectionSize; vec2 vEmissiveInfos; vec2 vLightmapInfos; vec2 vSpecularInfos; @@ -24,7 +21,6 @@ uniform Material mat4 diffuseMatrix; mat4 ambientMatrix; mat4 opacityMatrix; - mat4 reflectionMatrix; mat4 emissiveMatrix; mat4 lightmapMatrix; mat4 specularMatrix; @@ -42,6 +38,11 @@ uniform Material vec3 vAmbientColor; vec4 cameraInfo; + vec2 vReflectionInfos; + mat4 reflectionMatrix; + vec3 vReflectionPosition; + vec3 vReflectionSize; + #define ADDITIONAL_UBO_DECLARATION }; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx new file mode 100644 index 00000000000..c1157e90f43 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -0,0 +1,98 @@ +layout(std140, column_major) uniform; + +// layout(set = 0, binding = 0) uniform Harmonics +// { +// uniform vec3 vSphericalL00; +// uniform vec3 vSphericalL1_1; +// uniform vec3 vSphericalL10; +// uniform vec3 vSphericalL11; +// uniform vec3 vSphericalL2_2; +// uniform vec3 vSphericalL2_1; +// uniform vec3 vSphericalL20; +// uniform vec3 vSphericalL21; +// uniform vec3 vSphericalL22; +// uniform vec3 vSphericalX; +// uniform vec3 vSphericalY; +// uniform vec3 vSphericalZ; +// uniform vec3 vSphericalXX_ZZ; +// uniform vec3 vSphericalYY_ZZ; +// uniform vec3 vSphericalZZ; +// uniform vec3 vSphericalXY; +// uniform vec3 vSphericalYZ; +// uniform vec3 vSphericalZX; +// } + +uniform Material { + vec2 vLightmapInfos; + vec3 vBumpInfos; + + mat4 lightmapMatrix; + mat4 bumpMatrix; + vec2 vTangentSpaceParams; + vec4 vLightingIntensity; + float pointSize; + + vec2 vDebugMode; + + vec4 cameraInfo; + + vec2 vReflectionInfos; + mat4 reflectionMatrix; + vec3 vReflectionMicrosurfaceInfos; + vec3 vReflectionPosition; + vec3 vReflectionSize; + vec2 vReflectionFilteringInfo; + vec3 vReflectionDominantDirection; + vec3 vReflectionColor; + + vec3 vSphericalL00; + vec3 vSphericalL1_1; + vec3 vSphericalL10; + vec3 vSphericalL11; + vec3 vSphericalL2_2; + vec3 vSphericalL2_1; + vec3 vSphericalL20; + vec3 vSphericalL21; + vec3 vSphericalL22; + + vec3 vSphericalX; + vec3 vSphericalY; + vec3 vSphericalZ; + vec3 vSphericalXX_ZZ; + vec3 vSphericalYY_ZZ; + vec3 vSphericalZZ; + vec3 vSphericalXY; + vec3 vSphericalYZ; + vec3 vSphericalZX; + + float baseWeight; + vec4 vBaseColor; + float vBaseDiffuseRoughness; + vec4 vReflectanceInfo; + vec4 vSpecularColor; + vec3 vEmissionColor; + + vec2 vBaseWeightInfos; + mat4 baseWeightMatrix; + vec2 vBaseColorInfos; + mat4 baseColorMatrix; + vec2 vBaseDiffuseRoughnessInfos; + mat4 baseDiffuseRoughnessMatrix; + vec2 vSpecularWeightInfos; + mat4 specularWeightMatrix; + vec2 vSpecularColorInfos; + mat4 specularColorMatrix; + vec2 vBaseMetalRoughInfos; + mat4 baseMetalRoughMatrix; + vec2 vGeometryOpacityInfos; + mat4 geometryOpacityMatrix; + vec2 vEmissionInfos; + mat4 emissionMatrix; + vec2 vAmbientOcclusionInfos; + mat4 ambientOcclusionMatrix; + +#define ADDITIONAL_UBO_DECLARATION +}; + +#include +#include diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx new file mode 100644 index 00000000000..1053198bdf4 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx @@ -0,0 +1,115 @@ +struct albedoOpacityOutParams +{ + vec3 surfaceAlbedo; + float alpha; +}; + +#define pbr_inline +albedoOpacityOutParams albedoOpacityBlock( + in vec4 vAlbedoColor +#ifdef BASE_COLOR + ,in vec4 albedoTexture + ,in vec2 albedoInfos +#endif + , in float baseWeight +#ifdef BASE_WEIGHT + , in vec4 baseWeightTexture + , in vec2 vBaseWeightInfos +#endif +#ifdef OPACITY + ,in vec4 opacityMap + ,in vec2 vOpacityInfos +#endif +#ifdef DETAIL + ,in vec4 detailColor + ,in vec4 vDetailInfos +#endif +#ifdef DECAL + ,in vec4 decalColor + ,in vec4 vDecalInfos +#endif +) +{ + albedoOpacityOutParams outParams; + // _____________________________ Albedo Information ______________________________ + vec3 surfaceAlbedo = vAlbedoColor.rgb; + float alpha = vAlbedoColor.a; + + #ifdef BASE_COLOR + #if defined(ALPHAFROMALBEDO) || defined(ALPHATEST) + alpha *= albedoTexture.a; + #endif + + #ifdef BASE_COLOR_GAMMA + surfaceAlbedo *= toLinearSpace(albedoTexture.rgb); + #else + surfaceAlbedo *= albedoTexture.rgb; + #endif + + surfaceAlbedo *= albedoInfos.y; + #endif + + #ifndef DECAL_AFTER_DETAIL + #include + #endif + + #if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) + surfaceAlbedo *= vColor.rgb; + #endif + + #ifdef DETAIL + float detailAlbedo = 2.0 * mix(0.5, detailColor.r, vDetailInfos.y); + surfaceAlbedo.rgb = surfaceAlbedo.rgb * detailAlbedo * detailAlbedo; // should be pow(detailAlbedo, 2.2) but detailAlbedo² is close enough and cheaper to compute + #endif + + #ifdef DECAL_AFTER_DETAIL + #include + #endif + + #define CUSTOM_FRAGMENT_UPDATE_ALBEDO + + // According to OpenPBR: + // - for metals, base_weight is a factor to the base_color (F0, thus surfaceAlbedo in + // Babylons.js). + // - for dielectrics, base_weight is a factor to the diffuse BRDF (i.e. it should be + // applied in computeDiffuseLighting), but with the diffuse model *currently* used + // in Babylon.js, factoring it into the surfaceAlbedo is equivalent. + surfaceAlbedo *= baseWeight; + #ifdef BASE_WEIGHT + surfaceAlbedo *= baseWeightTexture.r; + #endif + + // _____________________________ Alpha Information _______________________________ + #ifdef OPACITY + #ifdef OPACITYRGB + alpha = getLuminance(opacityMap.rgb); + #else + alpha *= opacityMap.a; + #endif + + alpha *= vOpacityInfos.y; + #endif + + #if defined(VERTEXALPHA) || defined(INSTANCESCOLOR) && defined(INSTANCES) + alpha *= vColor.a; + #endif + + #if !defined(SS_LINKREFRACTIONTOTRANSPARENCY) && !defined(ALPHAFRESNEL) + #ifdef ALPHATEST + #if DEBUGMODE != 88 + if (alpha < ALPHATESTVALUE) + discard; + #endif + + #ifndef ALPHABLEND + // Prevent to blend with the canvas. + alpha = 1.0; + #endif + #endif + #endif + + outParams.surfaceAlbedo = surfaceAlbedo; + outParams.alpha = alpha; + + return outParams; +} diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx new file mode 100644 index 00000000000..aa96e0ca8cb --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -0,0 +1,33 @@ +vec4 finalColor = vec4( +#ifndef UNLIT + #ifdef REFLECTION + finalIrradiance + + #endif + #ifdef SPECULARTERM + finalSpecularScaled + + #endif + #ifdef REFLECTION + finalRadianceScaled + + #endif +#endif + finalDiffuse, + alpha); + +// _____________________________ LightMappping _____________________________________ +#ifdef LIGHTMAP + #ifndef LIGHTMAPEXCLUDED + #ifdef USELIGHTMAPASSHADOWMAP + finalColor.rgb *= lightmapColor.rgb; + #else + finalColor.rgb += lightmapColor.rgb; + #endif + #endif +#endif + +// _____________________________ EmissiveLight _____________________________________ +finalColor.rgb += finalEmission; + +#define CUSTOM_FRAGMENT_BEFORE_FOG + +// _____________________________ Finally ___________________________________________ +finalColor = max(finalColor, 0.0); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx new file mode 100644 index 00000000000..8dcb78aa4f0 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx @@ -0,0 +1,69 @@ +aggShadow = aggShadow / numLights; + +// ______________________________________________________________________________ +// _____________________________ Energy Conservation ___________________________ +// Apply Energy Conservation. +// _____________________________ IBL BRDF + Energy Cons ________________________________ +#if defined(ENVIRONMENTBRDF) + #ifdef MS_BRDF_ENERGY_CONSERVATION + vec3 baseSpecularEnergyConservationFactor = getEnergyConservationFactor(vec3(reflectanceF0), environmentBrdf); + vec3 coloredEnergyConservationFactor = getEnergyConservationFactor(specularEnvironmentR0, environmentBrdf); + #endif +#endif + +// _____________________________ Irradiance ______________________________________ +#ifdef REFLECTION + vec3 finalIrradiance = reflectionOut.environmentIrradiance; + + // Account for energy loss due to specular reflectance + vec3 baseSpecularEnergy = vec3(baseSpecularEnvironmentReflectance); + #if defined(ENVIRONMENTBRDF) + #ifdef MS_BRDF_ENERGY_CONSERVATION + baseSpecularEnergy *= baseSpecularEnergyConservationFactor; + #endif + #endif + finalIrradiance *= clamp(vec3(1.0) - baseSpecularEnergy, 0.0, 1.0); + finalIrradiance *= vLightingIntensity.z; + finalIrradiance *= surfaceAlbedo.rgb; + finalIrradiance *= aoOut.ambientOcclusionColor; +#endif + +// _____________________________ Specular ________________________________________ +#ifdef SPECULARTERM + vec3 finalSpecular = specularBase; + finalSpecular = max(finalSpecular, 0.0); + + vec3 finalSpecularScaled = finalSpecular * vLightingIntensity.x * vLightingIntensity.w; + + #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION) + finalSpecularScaled *= coloredEnergyConservationFactor; + #endif +#endif + +// _____________________________ Radiance ________________________________________ +#ifdef REFLECTION + vec3 finalRadiance = reflectionOut.environmentRadiance.rgb; + finalRadiance *= colorSpecularEnvironmentReflectance; + + vec3 finalRadianceScaled = finalRadiance * vLightingIntensity.z; + + #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION) + finalRadianceScaled *= coloredEnergyConservationFactor; + #endif +#endif + +// _____________________________ Highlights on Alpha _____________________________ +#ifdef ALPHABLEND + float luminanceOverAlpha = 0.0; + #if defined(REFLECTION) && defined(RADIANCEOVERALPHA) + luminanceOverAlpha += getLuminance(finalRadianceScaled); + #endif + + #if defined(SPECULARTERM) && defined(SPECULAROVERALPHA) + luminanceOverAlpha += getLuminance(finalSpecularScaled); + #endif + + #if defined(RADIANCEOVERALPHA) || defined(SPECULAROVERALPHA) + alpha = saturate(alpha + luminanceOverAlpha * luminanceOverAlpha); + #endif +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx new file mode 100644 index 00000000000..af4db665973 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx @@ -0,0 +1,36 @@ +#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + // "Base" specular reflectance is the amount of light prevented from penetrating the diffuse surface by the specular lobe. + // For dielectric materials, this is a greyscale value derived from the IOR and the maximum component of the specular colour. + // For metallic materials, this is vec3(1.0). i.e. no light penetrates to the diffuse surface. + vec3 baseSpecularEnvironmentReflectance = getReflectanceFromBRDFLookup(vec3(reflectanceF0), reflectivityOut.reflectanceF90, environmentBrdf); + + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + // For OpenPBR, we use a different specular lobe for metallic materials and then blend based on metalness. However, + // to do this correctly, we really need reflectivityOut to contain separate F0 and F90 values for purely dielectric + // and purely metal. Instead, the values are already a mix of dielectric and metallic values. + // So, for intermediate metallic values, the result isn't 100% correct but it seems to work well enough in practice. + // Because specular weight in OpenPBR removes the specular lobe entirely for metals, we do need the actual dielectric + // F0 value to pickup the weight from the dielectric lobe. + vec3 metalEnvironmentReflectance = reflectivityOut.specularWeight * getF82Specular(NdotV, reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, reflectivityOut.roughness); + vec3 dielectricEnvironmentReflectance = getReflectanceFromBRDFLookup(reflectivityOut.dielectricColorF0, reflectivityOut.colorReflectanceF90, environmentBrdf); + vec3 colorSpecularEnvironmentReflectance = mix(dielectricEnvironmentReflectance, metalEnvironmentReflectance, reflectivityOut.metallic); + #else + vec3 colorSpecularEnvironmentReflectance = getReflectanceFromBRDFLookup(reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, environmentBrdf); + #endif + + #ifdef RADIANCEOCCLUSION + colorSpecularEnvironmentReflectance *= seo; + #endif + + #ifdef HORIZONOCCLUSION + #ifdef BUMP + #ifdef REFLECTIONMAP_3D + colorSpecularEnvironmentReflectance *= eho; + #endif + #endif + #endif +#else + // Jones implementation of a well balanced fast analytical solution. + vec3 colorSpecularEnvironmentReflectance = getReflectanceFromAnalyticalBRDFLookup_Jones(NdotV, reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, sqrt(microSurface)); + vec3 baseSpecularEnvironmentReflectance = getReflectanceFromAnalyticalBRDFLookup_Jones(NdotV, vec3(reflectanceF0), reflectivityOut.reflectanceF90, sqrt(microSurface)); +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx new file mode 100644 index 00000000000..eed66449874 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx @@ -0,0 +1,135 @@ +struct reflectivityOutParams +{ + float roughness; + float diffuseRoughness; + float reflectanceF0; + vec3 reflectanceF90; + vec3 colorReflectanceF0; + vec3 colorReflectanceF90; + float metallic; + float specularWeight; + vec3 dielectricColorF0; +#if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + vec3 ambientOcclusionColor; +#endif +#if DEBUGMODE > 0 + #ifdef METALLIC_ROUGHNESS + vec4 surfaceMetallicColorMap; + #endif + vec3 metallicF0; +#endif +}; + +#define pbr_inline +reflectivityOutParams reflectivityBlock( + in vec4 reflectanceInfo + , in vec3 surfaceAlbedo + , in vec4 specularColor + , in float baseDiffuseRoughness +#ifdef BASE_DIFFUSE_ROUGHNESS + , in float baseDiffuseRoughnessTexture + , in vec2 baseDiffuseRoughnessInfos +#endif +#ifdef METALLIC_ROUGHNESS + , in vec3 reflectivityInfos + , in vec4 metallicRoughnessFromTexture +#endif +#if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + , in vec3 ambientOcclusionColorIn +#endif +#ifdef DETAIL + , in vec4 detailColor + , in vec4 vDetailInfos +#endif +) +{ + reflectivityOutParams outParams; + vec2 metallicRoughness = reflectanceInfo.rg; + float ior = reflectanceInfo.b; + #ifdef METALLIC_ROUGHNESS + #if DEBUGMODE > 0 + outParams.surfaceMetallicColorMap = metallicRoughnessFromTexture; + #endif + + #ifdef AOSTOREINMETALMAPRED + vec3 aoStoreInMetalMap = vec3(metallicRoughnessFromTexture.r, metallicRoughnessFromTexture.r, metallicRoughnessFromTexture.r); + outParams.ambientOcclusionColor = mix(ambientOcclusionColorIn, aoStoreInMetalMap, reflectivityInfos.z); + #endif + + metallicRoughness.r *= metallicRoughnessFromTexture.b; + metallicRoughness.g *= metallicRoughnessFromTexture.g; + #endif + + #ifdef DETAIL + float detailRoughness = mix(0.5, detailColor.b, vDetailInfos.w); + float loLerp = mix(0., metallicRoughness.g, detailRoughness * 2.); + float hiLerp = mix(metallicRoughness.g, 1., (detailRoughness - 0.5) * 2.); + metallicRoughness.g = mix(loLerp, hiLerp, step(detailRoughness, 0.5)); + #endif + + #define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS + + outParams.metallic = metallicRoughness.r; + outParams.roughness = metallicRoughness.g; + outParams.specularWeight = specularColor.a; + const float outsideIOR = 1.0; + float dielectricF0 = pow((ior - outsideIOR) / (ior + outsideIOR), 2.0) * outParams.specularWeight; + + #if DEBUGMODE > 0 + outParams.metallicF0 = vec3(dielectricF0) * specularColor.rgb; + #endif + + // Compute non-coloured reflectance. + // reflectanceF0 is the non-coloured reflectance used for blending between the diffuse and specular components. + // It represents the total percentage of light reflected by the specular lobe at normal incidence. + // In glTF's material model, the F0 value is multiplied by the maximum component of the specular colour. + + #if DIELECTRIC_SPECULAR_MODEL == DIELECTRIC_SPECULAR_MODEL_GLTF + float maxF0 = max(specularColor.r, max(specularColor.g, specularColor.b)); + outParams.reflectanceF0 = mix(dielectricF0 * maxF0, 1.0, outParams.metallic); + #else + outParams.reflectanceF0 = mix(dielectricF0, 1.0, outParams.metallic); + #endif + + + // Scale the reflectanceF90 by the IOR for values less than 1.5. + // This is an empirical hack to account for the fact that Schlick is tuned for IOR = 1.5 + // and an IOR of 1.0 should result in no visible glancing specular. + float f90Scale = clamp(2.0 * (ior - 1.0), 0.0, 1.0); + outParams.reflectanceF90 = vec3(mix(outParams.specularWeight * f90Scale, 1.0, outParams.metallic)); + + // Compute the coloured F0 reflectance. + // The coloured reflectance is the percentage of light reflected by the specular lobe at normal incidence. + // In glTF and OpenPBR, it is not the same thing as the percentage of light blocked from penetrating + // down to the diffuse lobe. The non-coloured F0 will be used for this (see below). + outParams.dielectricColorF0 = vec3(dielectricF0 * specularColor.rgb); + vec3 metallicColorF0 = surfaceAlbedo.rgb; + outParams.colorReflectanceF0 = mix(outParams.dielectricColorF0, metallicColorF0, outParams.metallic); + + // Now, compute the coloured reflectance at glancing angles based on the specular model. + #if (DIELECTRIC_SPECULAR_MODEL == DIELECTRIC_SPECULAR_MODEL_OPENPBR) + // In OpenPBR, the F90 is coloured using the specular colour for dielectrics. + vec3 dielectricColorF90 = specularColor.rgb * vec3(outParams.specularWeight) * vec3(f90Scale); + #else + // In glTF, the F90 is white for dielectrics. + vec3 dielectricColorF90 = vec3(outParams.specularWeight * f90Scale); + #endif + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + // In OpenPBR, we use the "F82" model for conductors. + // We'll use the F90 value to hold the F82 tint which will be used in the computation later. + vec3 conductorColorF90 = specularColor.rgb; + #else + // In glTF, the F90 colour for metals is white. + vec3 conductorColorF90 = vec3(1.0); + #endif + outParams.colorReflectanceF90 = mix(dielectricColorF90, conductorColorF90, outParams.metallic); + + float diffuseRoughness = baseDiffuseRoughness; +#ifdef BASE_DIFFUSE_ROUGHNESS + diffuseRoughness *= baseDiffuseRoughnessTexture * baseDiffuseRoughnessInfos.y; +#endif + + outParams.diffuseRoughness = diffuseRoughness; + + return outParams; +} diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx new file mode 100644 index 00000000000..d317ba67432 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -0,0 +1,117 @@ +uniform vec4 vEyePosition; + +uniform vec3 vReflectionColor; +uniform vec4 vBaseColor; +uniform float baseWeight; +uniform float vBaseDiffuseRoughness; + +// CUSTOM CONTROLS +uniform vec4 vLightingIntensity; + +uniform vec3 vEmissionColor; + +uniform float visibility; + +// Samplers +#ifdef BASE_COLOR +uniform vec2 vBaseColorInfos; +#endif + +#ifdef BASE_WEIGHT +uniform vec2 vBaseWeightInfos; +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS +uniform vec2 vBaseDiffuseRoughnessInfos; +#endif + +#ifdef AMBIENT_OCCLUSION +uniform vec4 vAmbientOcclusionInfos; +#endif + +#ifdef BUMP +uniform vec3 vBumpInfos; +uniform vec2 vTangentSpaceParams; +#endif + +#ifdef GEOMETRY_OPACITY +uniform vec2 vGeometryOpacityInfos; +#endif + +#ifdef EMISSION +uniform vec2 vEmissionInfos; +#endif + +#ifdef LIGHTMAP +uniform vec2 vLightmapInfos; +#endif + +#ifdef METALLIC_ROUGHNESS +uniform vec2 vBaseMetalRoughInfos; +#endif + +// Refraction Reflection +#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(SS_REFRACTION) || defined(PREPASS) +uniform mat4 view; +#endif + +// Reflection +#ifdef REFLECTION + uniform vec2 vReflectionInfos; + + #ifdef REALTIME_FILTERING + uniform vec2 vReflectionFilteringInfo; + #endif + uniform mat4 reflectionMatrix; + uniform vec3 vReflectionMicrosurfaceInfos; + #if defined(USEIRRADIANCEMAP) && defined(USE_IRRADIANCE_DOMINANT_DIRECTION) + uniform vec3 vReflectionDominantDirection; + #endif + + #if defined(USE_LOCAL_REFLECTIONMAP_CUBIC) && defined(REFLECTIONMAP_CUBIC) + uniform vec3 vReflectionPosition; + uniform vec3 vReflectionSize; + #endif +#endif + +#ifdef PREPASS + #ifdef SS_SCATTERING + uniform float scatteringDiffusionProfile; + #endif +#endif + +#if DEBUGMODE > 0 + uniform vec2 vDebugMode; +#endif + +#ifdef DETAIL + uniform vec4 vDetailInfos; +#endif + +#include + +#ifdef USESPHERICALFROMREFLECTIONMAP + #ifdef SPHERICAL_HARMONICS + uniform vec3 vSphericalL00; + uniform vec3 vSphericalL1_1; + uniform vec3 vSphericalL10; + uniform vec3 vSphericalL11; + uniform vec3 vSphericalL2_2; + uniform vec3 vSphericalL2_1; + uniform vec3 vSphericalL20; + uniform vec3 vSphericalL21; + uniform vec3 vSphericalL22; + #else + uniform vec3 vSphericalX; + uniform vec3 vSphericalY; + uniform vec3 vSphericalZ; + uniform vec3 vSphericalXX_ZZ; + uniform vec3 vSphericalYY_ZZ; + uniform vec3 vSphericalZZ; + uniform vec3 vSphericalXY; + uniform vec3 vSphericalYZ; + uniform vec3 vSphericalZX; + #endif +#endif + +#define ADDITIONAL_FRAGMENT_DECLARATION diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx new file mode 100644 index 00000000000..f9955dbdf73 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -0,0 +1,97 @@ +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_SAMPLERNAME_,baseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_SAMPLERNAME_,baseDiffuseRoughness) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_SAMPLERNAME_,baseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight,_SAMPLERNAME_,specularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor,_SAMPLERNAME_,specularColor) +#include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) +#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) + +#include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) + +// Reflection +#ifdef REFLECTION + #ifdef REFLECTIONMAP_3D + #define sampleReflection(s, c) textureCube(s, c) + + uniform samplerCube reflectionSampler; + + #ifdef LODBASEDMICROSFURACE + #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l) + #else + uniform samplerCube reflectionSamplerLow; + uniform samplerCube reflectionSamplerHigh; + #endif + + #ifdef USEIRRADIANCEMAP + uniform samplerCube irradianceSampler; + #endif + #else + #define sampleReflection(s, c) texture2D(s, c) + + uniform sampler2D reflectionSampler; + + #ifdef LODBASEDMICROSFURACE + #define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l) + #else + uniform sampler2D reflectionSamplerLow; + uniform sampler2D reflectionSamplerHigh; + #endif + + #ifdef USEIRRADIANCEMAP + uniform sampler2D irradianceSampler; + #endif + #endif + + #ifdef REFLECTIONMAP_SKYBOX + varying vec3 vPositionUVW; + #else + #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) + varying vec3 vDirectionW; + #endif + #endif +#endif + +#ifdef ENVIRONMENTBRDF + uniform sampler2D environmentBrdfSampler; +#endif + +// SUBSURFACE +#ifdef SUBSURFACE + #ifdef SS_REFRACTION + #ifdef SS_REFRACTIONMAP_3D + #define sampleRefraction(s, c) textureCube(s, c) + + uniform samplerCube refractionSampler; + + #ifdef LODBASEDMICROSFURACE + #define sampleRefractionLod(s, c, l) textureCubeLodEXT(s, c, l) + #else + uniform samplerCube refractionSamplerLow; + uniform samplerCube refractionSamplerHigh; + #endif + #else + #define sampleRefraction(s, c) texture2D(s, c) + + uniform sampler2D refractionSampler; + + #ifdef LODBASEDMICROSFURACE + #define sampleRefractionLod(s, c, l) texture2DLodEXT(s, c, l) + #else + uniform sampler2D refractionSamplerLow; + uniform sampler2D refractionSamplerHigh; + #endif + #endif + #endif + + #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness,_SAMPLERNAME_,thickness) + #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_SAMPLERNAME_,refractionIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_SAMPLERNAME_,translucencyIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_SAMPLERNAME_,translucencyColor) +#endif + +#ifdef IBL_CDF_FILTERING + uniform sampler2D icdfSampler; +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx new file mode 100644 index 00000000000..4997164b647 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -0,0 +1,111 @@ +uniform mat4 view; +uniform mat4 viewProjection; +uniform vec4 vEyePosition; +#ifdef MULTIVIEW + mat4 viewProjectionR; +#endif + +#ifdef BASE_COLOR +uniform vec2 vBaseColorInfos; +uniform mat4 baseColorMatrix; +#endif + +#ifdef BASE_WEIGHT +uniform mat4 baseWeightMatrix; +uniform vec2 vBaseWeightInfos; +#endif + +uniform float vBaseDiffuseRoughness; +#ifdef BASE_DIFFUSE_ROUGHNESS +uniform mat4 baseDiffuseRoughnessMatrix; +uniform vec2 vBaseDiffuseRoughnessInfos; +#endif + +#ifdef GEOMETRY_OPACITY +uniform mat4 geometryOpacityMatrix; +uniform vec2 vGeometryOpacityInfos; +#endif + +#ifdef AMBIENT_OCCLUSION +uniform vec2 vAmbientOcclusionInfos; +uniform mat4 ambientOcclusionMatrix; +#endif + +#ifdef EMISSION +uniform vec2 vEmissionInfos; +uniform mat4 emissionMatrix; +#endif + +#ifdef LIGHTMAP +uniform vec2 vLightmapInfos; +uniform mat4 lightmapMatrix; +#endif + +#ifdef METALLIC_ROUGHNESS +uniform vec2 vBaseMetalRoughInfos; +uniform mat4 baseMetalRoughMatrix; +#endif + +#ifdef SPECULAR_WEIGHT +uniform vec2 vSpecularWeightInfos; +uniform mat4 specularWeightMatrix; +#endif + +#ifdef SPECULAR_COLOR +uniform vec2 vSpecularColorInfos; +uniform mat4 specularColorMatrix; +#endif + +#ifdef BUMP +uniform vec3 vBumpInfos; +uniform mat4 bumpMatrix; +#endif + +#ifdef POINTSIZE +uniform float pointSize; +#endif + +uniform vec4 cameraInfo; + +// Reflection +#ifdef REFLECTION + uniform vec2 vReflectionInfos; + uniform mat4 reflectionMatrix; +#endif + +#ifdef NORMAL + #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) + #ifdef USESPHERICALFROMREFLECTIONMAP + #ifdef SPHERICAL_HARMONICS + uniform vec3 vSphericalL00; + uniform vec3 vSphericalL1_1; + uniform vec3 vSphericalL10; + uniform vec3 vSphericalL11; + uniform vec3 vSphericalL2_2; + uniform vec3 vSphericalL2_1; + uniform vec3 vSphericalL20; + uniform vec3 vSphericalL21; + uniform vec3 vSphericalL22; + #else + uniform vec3 vSphericalX; + uniform vec3 vSphericalY; + uniform vec3 vSphericalZ; + uniform vec3 vSphericalXX_ZZ; + uniform vec3 vSphericalYY_ZZ; + uniform vec3 vSphericalZZ; + uniform vec3 vSphericalXY; + uniform vec3 vSphericalYZ; + uniform vec3 vSphericalZX; + #endif + #endif + #endif +#endif + +#ifdef DETAIL +uniform vec4 vDetailInfos; +uniform mat4 detailMatrix; +#endif + +#include + +#define ADDITIONAL_VERTEX_DECLARATION diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrBRDFFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrBRDFFunctions.fx index db6a8130573..a6a53279de4 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrBRDFFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrBRDFFunctions.fx @@ -9,7 +9,7 @@ #define CONDUCTOR_SPECULAR_MODEL_GLTF 0 #define CONDUCTOR_SPECULAR_MODEL_OPENPBR 1 -#ifndef PBR_VERTEX_SHADER +#if !defined(PBR_VERTEX_SHADER) && !defined(OPENPBR_VERTEX_SHADER) // ______________________________________________________________________ // diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx index 47a2252ac9d..cddb7c45b7a 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx @@ -32,10 +32,6 @@ uniform Material { vec2 vLightmapInfos; vec3 vReflectivityInfos; vec2 vMicroSurfaceSamplerInfos; - vec2 vReflectionInfos; - vec2 vReflectionFilteringInfo; - vec3 vReflectionPosition; - vec3 vReflectionSize; vec3 vBumpInfos; mat4 albedoMatrix; mat4 baseWeightMatrix; @@ -48,14 +44,10 @@ uniform Material { mat4 microSurfaceSamplerMatrix; mat4 bumpMatrix; vec2 vTangentSpaceParams; - mat4 reflectionMatrix; - vec3 vReflectionColor; vec4 vAlbedoColor; float baseWeight; float baseDiffuseRoughness; vec4 vLightingIntensity; - vec3 vReflectionMicrosurfaceInfos; - vec3 vReflectionDominantDirection; float pointSize; vec4 vReflectivityColor; vec3 vEmissiveColor; @@ -68,7 +60,17 @@ uniform Material { mat4 metallicReflectanceMatrix; vec2 vReflectanceInfos; mat4 reflectanceMatrix; + vec4 cameraInfo; + vec2 vReflectionInfos; + mat4 reflectionMatrix; + vec3 vReflectionMicrosurfaceInfos; + vec3 vReflectionPosition; + vec3 vReflectionSize; + vec2 vReflectionFilteringInfo; + vec3 vReflectionDominantDirection; + vec3 vReflectionColor; + vec3 vSphericalL00; vec3 vSphericalL1_1; vec3 vSphericalL10; @@ -89,8 +91,6 @@ uniform Material { vec3 vSphericalYZ; vec3 vSphericalZX; - vec4 cameraInfo; - #define ADDITIONAL_UBO_DECLARATION }; diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx new file mode 100644 index 00000000000..32da1a6614d --- /dev/null +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -0,0 +1,372 @@ +#define OPENPBR_FRAGMENT_SHADER + +#define CUSTOM_FRAGMENT_EXTENSION + +#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) +#extension GL_OES_standard_derivatives : enable +#endif + +#ifdef LODBASEDMICROSFURACE +#extension GL_EXT_shader_texture_lod : enable +#endif + +#define CUSTOM_FRAGMENT_BEGIN + +#ifdef LOGARITHMICDEPTH +#extension GL_EXT_frag_depth : enable +#endif + +#include[SCENE_MRT_COUNT] + +precision highp float; +#include + +// Forces linear space for image processing +#ifndef FROMLINEARSPACE + #define FROMLINEARSPACE +#endif + +// Declaration +#include<__decl__openpbrFragment> + +#include +#include<__decl__lightFragment>[0..maxSimultaneousLights] +#include +#include +#include +#include +#include + +// Helper Functions +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef REFLECTION + #include +#endif + +#define CUSTOM_FRAGMENT_DEFINITIONS + +#include +#include +#include +#include +#include + +// _____________________________ MAIN FUNCTION ____________________________ +void main(void) { + + #define CUSTOM_FRAGMENT_MAIN_BEGIN + + #include + + // _____________________________ Geometry Information ____________________________ + #include + + #include + + #include + + // _____________________________ Albedo & Opacity ______________________________ + albedoOpacityOutParams albedoOpacityOut; + +#ifdef BASE_COLOR + vec4 baseColorFromTexture = texture2D(baseColorSampler, vBaseColorUV + uvOffset); +#endif + +#ifdef BASE_WEIGHT + vec4 baseWeightFromTexture = texture2D(baseWeightSampler, vBaseWeightUV + uvOffset); +#endif + +#ifdef OPACITY + vec4 opacityMap = texture2D(opacitySampler, vOpacityUV + uvOffset); +#endif + +#ifdef DECAL + vec4 decalColor = texture2D(decalSampler, vDecalUV + uvOffset); +#endif + + albedoOpacityOut = albedoOpacityBlock( + vBaseColor + #ifdef BASE_COLOR + , baseColorFromTexture + , vBaseColorInfos + #endif + , baseWeight + #ifdef BASE_WEIGHT + , baseWeightFromTexture + , vBaseWeightInfos + #endif + #ifdef OPACITY + , opacityMap + , vOpacityInfos + #endif + #ifdef DETAIL + , detailColor + , vDetailInfos + #endif + #ifdef DECAL + , decalColor + , vDecalInfos + #endif + ); + + vec3 surfaceAlbedo = albedoOpacityOut.surfaceAlbedo; + float alpha = albedoOpacityOut.alpha; + + #define CUSTOM_FRAGMENT_UPDATE_ALPHA + + #include + + #define CUSTOM_FRAGMENT_BEFORE_LIGHTS + + +// MPBR =mix(Sambient-medium,Msurface,α) whereα =geometry_opacity +// Msurface =layer(Mcoated-base,Sfuzz,F) whereF =fuzz_weight +// Mcoated-base =layer(Mbase,Scoat,C) whereC =coat_weight + +// Mbase =mix(Mdielectric-base,Smetal,M) whereM =base_metalness +// Mdielectric-base =mix(Mopaque-base,Stranslucent-base,T) whereT =transmission_weight +// Mopaque-base =mix(Mglossy-diffuse,Ssubsurface,S) whereS =subsurface_weight +// Mglossy-diffuse =layer(Sdiffuse,Sgloss) + + + + // _____________________________ AO _______________________________ + ambientOcclusionOutParams aoOut; + +#ifdef AMBIENT_OCCLUSION + vec3 ambientOcclusionFromTexture = texture2D(ambientOcclusionSampler, vAmbientOcclusionUV + uvOffset).rgb; +#endif + + aoOut = ambientOcclusionBlock( + #ifdef AMBIENT_OCCLUSION + ambientOcclusionFromTexture, + vAmbientOcclusionInfos + #endif + ); + + #include + +#ifdef UNLIT + vec3 diffuseBase = vec3(1., 1., 1.); +#else // !UNLIT + + // _____________________________ Reflectivity (Rename this to IBL) _______________________________ + + reflectivityOutParams reflectivityOut; + +#ifdef METALLIC_ROUGHNESS + vec4 metallicRoughnessFromTexture = texture2D(baseMetalRoughSampler, vBaseMetalRoughUV + uvOffset); +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + float baseDiffuseRoughnessFromTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; +#endif + +vec4 specularColor = vSpecularColor; +#ifdef SPECULAR_COLOR + vec4 specularColorFromTexture = texture2D(specularColorSampler, vSpecularColorUV + uvOffset); + #ifdef SPECULAR_COLOR_GAMMA + specularColorFromTexture = toLinearSpace(specularColorFromTexture); + #endif + + specularColor.rgb *= specularColorFromTexture.rgb; +#endif +#ifdef SPECULAR_WEIGHT + vec4 specularWeightFromTexture = texture2D(specularWeightSampler, vSpecularWeightUV + uvOffset); + #ifdef SPECULAR_WEIGHT_GAMMA + specularWeightFromTexture = toLinearSpace(specularWeightFromTexture); + #endif + + // If loaded from a glTF, the specular_weight is stored in the alpha channel. + // Otherwise, it's expected to just be a greyscale texture. + #ifdef SPECULAR_WEIGHT_USE_ALPHA_ONLY + specularColor.a *= specularWeightFromTexture.a; + #else + specularColor.rgb *= specularWeightFromTexture.rgb; + #endif +#endif + + reflectivityOut = reflectivityBlock( + vReflectanceInfo + , surfaceAlbedo + , specularColor + , vBaseDiffuseRoughness + #ifdef BASE_DIFFUSE_ROUGHNESS + , baseDiffuseRoughnessFromTexture + , vBaseDiffuseRoughnessInfos + #endif + #ifdef METALLIC_ROUGHNESS + , vec3(vBaseMetalRoughInfos, 1.0f) + , metallicRoughnessFromTexture + #ifdef AOSTOREINMETALMAPRED + , aoOut.ambientOcclusionColor + #endif + #endif + #ifdef DETAIL + , detailColor + , vDetailInfos + #endif + ); + + float roughness = reflectivityOut.roughness; + float diffuseRoughness = reflectivityOut.diffuseRoughness; + + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; + #endif + + // _____________________________ Compute Geometry info _________________________________ + #include + + // _____________________________ Reflection Info _______________________________________ + #ifdef REFLECTION + reflectionOutParams reflectionOut; + + #ifndef USE_CUSTOM_REFLECTION + reflectionOut = reflectionBlock( + vPositionW + , normalW + , alphaG + , vReflectionMicrosurfaceInfos + , vReflectionInfos + , vReflectionColor + #ifdef ANISOTROPIC + , anisotropicOut + #endif + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , NdotVUnclamped + #endif + #ifdef LINEARSPECULARREFLECTION + , roughness + #endif + , reflectionSampler + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + , vEnvironmentIrradiance + #endif + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + , reflectionMatrix + #endif + #ifdef USEIRRADIANCEMAP + , irradianceSampler + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + , vReflectionDominantDirection + #endif + #endif + #ifndef LODBASEDMICROSFURACE + , reflectionSamplerLow + , reflectionSamplerHigh + #endif + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + #endif + #endif + , viewDirectionW + , diffuseRoughness + , surfaceAlbedo + ); + #else + #define CUSTOM_REFLECTION + #endif + #endif + + // _________________________ Specular Environment Reflectance __________________________ + float reflectanceF0 = reflectivityOut.reflectanceF0; + vec3 specularEnvironmentR0 = reflectivityOut.colorReflectanceF0; + vec3 specularEnvironmentR90 = reflectivityOut.colorReflectanceF90; + #include + + // _____________________________ Direct Lighting Info __________________________________ + #include + + // TODO: lightFragment references cloatcoatOut, subsurfaceOut, etc. + // lightFragment shouldn't know what layer it's working on. + // Instead, we should define values for lightFragment to use here, defining + // conditions like F0, F90, etc. + // Or we could convert lightFragment to be a function that returns the diffuse + // or specular contribution, given the reflectance inputs? + // e.g. lighting contributions from clearcoat, subsurface, base layer, etc. need + // to be computed separately. + // #include[0..maxSimultaneousLights] + + // _____________________________ Compute Final Lit Components ________________________ + #include +#endif // !UNLIT + + // #include + // _____________________________ Diffuse ________________________________________ + vec3 finalDiffuse = diffuseBase; + finalDiffuse *= surfaceAlbedo; + + finalDiffuse = max(finalDiffuse, 0.0); + finalDiffuse *= vLightingIntensity.x; + + // _____________________________ Emissive ________________________________________ + vec3 finalEmission = vEmissionColor; + #ifdef EMISSION + vec3 emissionColorTex = texture2D(emissionSampler, vEmissionUV + uvOffset).rgb; + #ifdef EMISSION_GAMMA + finalEmission *= toLinearSpace(emissionColorTex.rgb); + #else + finalEmission *= emissionColorTex.rgb; + #endif + finalEmission *= vEmissionInfos.y; + #endif + finalEmission *= vLightingIntensity.y; + + // ______________________________ Ambient ________________________________________ + #ifdef AMBIENT_OCCLUSION + finalDiffuse *= mix(vec3(1.), aoOut.ambientOcclusionColor, 1.0 - vAmbientOcclusionInfos.y); + #endif + + #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION + + #include + + #include + #include(color, finalColor) + #include + + #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR + +#ifdef PREPASS + #include +#endif + +#if !defined(PREPASS) || defined(WEBGL2) + gl_FragColor = finalColor; +#endif + + #include + +#if ORDER_INDEPENDENT_TRANSPARENCY + if (fragDepth == nearestDepth) { + frontColor.rgb += finalColor.rgb * finalColor.a * alphaMultiplier; + // Cancels the 1 - a initial value operation + frontColor.a = 1.0 - alphaMultiplier * (1.0 - finalColor.a); + } else { + backColor += finalColor; + } +#endif + + #include + + #define CUSTOM_FRAGMENT_MAIN_END + +} diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx new file mode 100644 index 00000000000..1f3ffdf2f8c --- /dev/null +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -0,0 +1,256 @@ +#define OPENPBR_VERTEX_SHADER + +#define CUSTOM_VERTEX_EXTENSION + +precision highp float; + +#include<__decl__openpbrVertex> + +#define CUSTOM_VERTEX_BEGIN + +// Attributes +attribute vec3 position; +#ifdef NORMAL +attribute vec3 normal; +#endif +#ifdef TANGENT +attribute vec4 tangent; +#endif +#ifdef UV1 +attribute vec2 uv; +#endif +#include[2..7] +#include[1..7] +#ifdef VERTEXCOLOR +attribute vec4 color; +#endif + +#include +#include +#include +#include + +#include +#include + +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) +#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) + +#include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) +#include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) + +// Output +varying vec3 vPositionW; +#if DEBUGMODE > 0 + varying vec4 vClipSpacePosition; +#endif + +#ifdef NORMAL + varying vec3 vNormalW; + #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) + varying vec3 vEnvironmentIrradiance; + + #include + #endif +#endif + +#if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) +varying vec4 vColor; +#endif + +// This is just including TBN, if needed. "Bump" isn't really a great name. +#include +#include +#include +#include<__decl__lightVxFragment>[0..maxSimultaneousLights] + +#include +#include[0..maxSimultaneousMorphTargets] + +#ifdef REFLECTIONMAP_SKYBOX +varying vec3 vPositionUVW; +#endif + +#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) +varying vec3 vDirectionW; +#endif + +#include +#define CUSTOM_VERTEX_DEFINITIONS + +void main(void) { + + #define CUSTOM_VERTEX_MAIN_BEGIN + + vec3 positionUpdated = position; +#ifdef NORMAL + vec3 normalUpdated = normal; +#endif +#ifdef TANGENT + vec4 tangentUpdated = tangent; +#endif +#ifdef UV1 + vec2 uvUpdated = uv; +#endif +#ifdef UV2 + vec2 uv2Updated = uv2; +#endif +#ifdef VERTEXCOLOR + vec4 colorUpdated = color; +#endif + +#include +#include[0..maxSimultaneousMorphTargets] + +#ifdef REFLECTIONMAP_SKYBOX + vPositionUVW = positionUpdated; +#endif + +#define CUSTOM_VERTEX_UPDATE_POSITION + +#define CUSTOM_VERTEX_UPDATE_NORMAL + +#include + +#if defined(PREPASS) && ((defined(PREPASS_VELOCITY) || defined(PREPASS_VELOCITY_LINEAR)) && !defined(BONES_VELOCITY_ENABLED) + // Compute velocity before bones computation + vCurrentPosition = viewProjection * finalWorld * vec4(positionUpdated, 1.0); + vPreviousPosition = previousViewProjection * finalPreviousWorld * vec4(positionUpdated, 1.0); +#endif + +#include +#include + + vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0); + vPositionW = vec3(worldPos); + +#ifdef PREPASS + #include +#endif + +#ifdef NORMAL + mat3 normalWorld = mat3(finalWorld); + + #if defined(INSTANCES) && defined(THIN_INSTANCES) + vNormalW = normalUpdated / vec3(dot(normalWorld[0], normalWorld[0]), dot(normalWorld[1], normalWorld[1]), dot(normalWorld[2], normalWorld[2])); + vNormalW = normalize(normalWorld * vNormalW); + #else + #ifdef NONUNIFORMSCALING + normalWorld = transposeMat3(inverseMat3(normalWorld)); + #endif + + vNormalW = normalize(normalWorld * normalUpdated); + #endif + + #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) + #if BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LAMBERT && BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LEGACY + // Bend the normal towards the viewer based on the diffuse roughness + vec3 viewDirectionW = normalize(vEyePosition.xyz - vPositionW); + + #if !defined(NATIVE) && !defined(WEBGPU) + // Next two lines fixes a flickering that occurs on some specific circumstances on MacOS/iOS + // See https://forum.babylonjs.com/t/needdepthprepass-creates-flickering-in-8-6-2/58421/12 + // Note that the variable passed to isnan doesn't matter... + bool bbb = any(isnan(position)); + if (bbb) { } + #endif + + float NdotV = max(dot(vNormalW, viewDirectionW), 0.0); + vec3 roughNormal = mix(vNormalW, viewDirectionW, (0.5 * (1.0 - NdotV)) * vBaseDiffuseRoughness); + vec3 reflectionVector = vec3(reflectionMatrix * vec4(roughNormal, 0)).xyz; + #else + vec3 reflectionVector = vec3(reflectionMatrix * vec4(vNormalW, 0)).xyz; + #endif + #ifdef REFLECTIONMAP_OPPOSITEZ + reflectionVector.z *= -1.0; + #endif + vEnvironmentIrradiance = computeEnvironmentIrradiance(reflectionVector); + #endif +#endif + +#define CUSTOM_VERTEX_UPDATE_WORLDPOS + +#ifdef MULTIVIEW + if (gl_ViewID_OVR == 0u) { + gl_Position = viewProjection * worldPos; + } else { + gl_Position = viewProjectionR * worldPos; + } +#else + gl_Position = viewProjection * worldPos; +#endif + +#if DEBUGMODE > 0 + vClipSpacePosition = gl_Position; +#endif + +#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) + vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0))); +#endif + + // Texture coordinates +#ifndef UV1 + vec2 uvUpdated = vec2(0., 0.); +#endif +#ifndef UV2 + vec2 uv2Updated = vec2(0., 0.); +#endif +#ifdef MAINUV1 + vMainUV1 = uvUpdated; +#endif +#ifdef MAINUV2 + vMainUV2 = uv2Updated; +#endif + + #include[3..7] + + #include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor,_MATRIXNAME_,albedo,_INFONAME_,BaseColorInfos.x) + #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_MATRIXNAME_,baseWeight,_INFONAME_,BaseWeightInfos.x) + #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_MATRIXNAME_,baseDiffuseRoughness,_INFONAME_,BaseDiffuseRoughnessInfos.x) + #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_MATRIXNAME_,baseMetalRough,_INFONAME_,BaseMetalRoughInfos.x) + #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight,_MATRIXNAME_,specularWeight,_INFONAME_,SpecularWeightInfos.x) + #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor,_MATRIXNAME_,specularColor,_INFONAME_,SpecularColorInfos.x) + #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) + #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) + + #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_MATRIXNAME_,ambientOcclusion,_INFONAME_,AmbientOcclusionInfos.x) + #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) + #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) + #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) + #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) + + // TBN +#include + + // Clip plane +#include + + // Fog +#include + + // Shadows +#include[0..maxSimultaneousLights] + + // Vertex color +#include + + // Point size +#if defined(POINTSIZE) && !defined(WEBGPU) + gl_PointSize = pointSize; +#endif + + // Log. depth +#include + +#define CUSTOM_VERTEX_MAIN_END + +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/backgroundUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/backgroundUboDeclaration.fx index 98551a79444..f6750a15a3f 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/backgroundUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/backgroundUboDeclaration.fx @@ -1,10 +1,7 @@ uniform vPrimaryColor: vec4f; uniform vPrimaryColorShadow: vec4f; -uniform vDiffuseInfos: vec2f; -uniform vReflectionInfos: vec2f; -uniform diffuseMatrix: mat4x4f; -uniform reflectionMatrix: mat4x4f; -uniform vReflectionMicrosurfaceInfos: vec3f; +uniform vDiffuseInfos : vec2f; +uniform diffuseMatrix : mat4x4f; uniform fFovMultiplier: f32; uniform pointSize: f32; @@ -14,4 +11,8 @@ uniform vBackgroundCenter: vec3f; uniform vReflectionControl: vec4f; uniform projectedGroundInfos: vec2f; +uniform vReflectionInfos : vec2f; +uniform reflectionMatrix : mat4x4f; +uniform vReflectionMicrosurfaceInfos : vec3f; + #include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/defaultUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/defaultUboDeclaration.fx index 5aec9a38d81..fe0b782bc3c 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/defaultUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/defaultUboDeclaration.fx @@ -10,9 +10,6 @@ uniform emissiveRightColor: vec4f; uniform vDiffuseInfos: vec2f; uniform vAmbientInfos: vec2f; uniform vOpacityInfos: vec2f; -uniform vReflectionInfos: vec2f; -uniform vReflectionPosition: vec3f; -uniform vReflectionSize: vec3f; uniform vEmissiveInfos: vec2f; uniform vLightmapInfos: vec2f; uniform vSpecularInfos: vec2f; @@ -20,7 +17,6 @@ uniform vBumpInfos: vec3f; uniform diffuseMatrix: mat4x4f; uniform ambientMatrix: mat4x4f; uniform opacityMatrix: mat4x4f; -uniform reflectionMatrix: mat4x4f; uniform emissiveMatrix: mat4x4f; uniform lightmapMatrix: mat4x4f; uniform specularMatrix: mat4x4f; @@ -37,6 +33,10 @@ uniform vEmissiveColor: vec3f; uniform vDiffuseColor: vec4f; uniform vAmbientColor: vec3f; uniform cameraInfo: vec4f; +uniform vReflectionInfos: vec2f; +uniform reflectionMatrix: mat4x4f; +uniform vReflectionPosition: vec3f; +uniform vReflectionSize: vec3f; #define ADDITIONAL_UBO_DECLARATION diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx new file mode 100644 index 00000000000..a401a7e0a8d --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -0,0 +1,74 @@ + +uniform vLightmapInfos: vec2f; +uniform vBumpInfos: vec3f; + +uniform lightmapMatrix: mat4x4f; +uniform bumpMatrix: mat4x4f; +uniform vTangentSpaceParams: vec2f; +uniform vLightingIntensity: vec4f; +uniform pointSize: f32; + +uniform vDebugMode: vec2f; + +uniform cameraInfo: vec4f; + +uniform vReflectionInfos: vec2f; +uniform reflectionMatrix: mat4x4f; +uniform vReflectionMicrosurfaceInfos: vec3f; +uniform vReflectionPosition: vec3f; +uniform vReflectionSize: vec3f; +uniform vReflectionFilteringInfo: vec2f; +uniform vReflectionDominantDirection: vec3f; +uniform vReflectionColor: vec3f; + +uniform vSphericalL00: vec3f; +uniform vSphericalL1_1: vec3f; +uniform vSphericalL10: vec3f; +uniform vSphericalL11: vec3f; +uniform vSphericalL2_2: vec3f; +uniform vSphericalL2_1: vec3f; +uniform vSphericalL20: vec3f; +uniform vSphericalL21: vec3f; +uniform vSphericalL22: vec3f; + +uniform vSphericalX: vec3f; +uniform vSphericalY: vec3f; +uniform vSphericalZ: vec3f; +uniform vSphericalXX_ZZ: vec3f; +uniform vSphericalYY_ZZ: vec3f; +uniform vSphericalZZ: vec3f; +uniform vSphericalXY: vec3f; +uniform vSphericalYZ: vec3f; +uniform vSphericalZX: vec3f; + +uniform baseWeight: f32; +uniform vBaseColor: vec4f; +uniform vBaseDiffuseRoughness: f32; +uniform vReflectanceInfo: vec4f; +uniform vSpecularColor: vec4f; +uniform vEmissionColor: vec3f; + +uniform vBaseWeightInfos: vec2f; +uniform baseWeightMatrix: mat4x4f; +uniform vBaseColorInfos: vec2f; +uniform baseColorMatrix: mat4x4f; +uniform vBaseDiffuseRoughnessInfos: vec2f; +uniform baseDiffuseRoughnessMatrix: mat4x4f; +uniform vSpecularWeightInfos: vec2f; +uniform specularWeightMatrix: mat4x4f; +uniform vSpecularColorInfos: vec2f; +uniform specularColorMatrix: mat4x4f; +uniform vBaseMetalRoughInfos: vec2f; +uniform baseMetalRoughMatrix: mat4x4f; +uniform vGeometryOpacityInfos: vec2f; +uniform geometryOpacityMatrix: mat4x4f; +uniform vEmissionInfos: vec2f; +uniform emissionMatrix: mat4x4f; +uniform vAmbientOcclusionInfos: vec2f; +uniform ambientOcclusionMatrix: mat4x4f; + +#define ADDITIONAL_UBO_DECLARATION + + +#include +#include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx new file mode 100644 index 00000000000..beeab50f8ec --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx @@ -0,0 +1,116 @@ +struct albedoOpacityOutParams +{ + surfaceAlbedo: vec3f, + alpha: f32 +}; + +#define pbr_inline +fn albedoOpacityBlock( + vAlbedoColor: vec4f +#ifdef BASE_COLOR + ,albedoTexture: vec4f + ,albedoInfos: vec2f +#endif + , baseWeight: f32 +#ifdef BASE_WEIGHT + , baseWeightTexture: vec4f + , vBaseWeightInfos: vec2f +#endif +#ifdef OPACITY + ,opacityMap: vec4f + ,vOpacityInfos: vec2f +#endif +#ifdef DETAIL + ,detailColor: vec4f + ,vDetailInfos: vec4f +#endif +#ifdef DECAL + ,decalColor: vec4f + ,vDecalInfos: vec4f +#endif +) -> albedoOpacityOutParams +{ + var outParams: albedoOpacityOutParams; + // _____________________________ Albedo Information ______________________________ + var surfaceAlbedo: vec3f = vAlbedoColor.rgb; + var alpha: f32 = vAlbedoColor.a; + + #ifdef BASE_COLOR + #if defined(ALPHAFROMALBEDO) || defined(ALPHATEST) + alpha *= albedoTexture.a; + #endif + + #ifdef BASE_COLOR_GAMMA + surfaceAlbedo *= toLinearSpaceVec3(albedoTexture.rgb); + #else + surfaceAlbedo *= albedoTexture.rgb; + #endif + + surfaceAlbedo *= albedoInfos.y; + #endif + + #ifndef DECAL_AFTER_DETAIL + #include + #endif + + #if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) + surfaceAlbedo *= fragmentInputs.vColor.rgb; + #endif + + #ifdef DETAIL + var detailAlbedo: f32 = 2.0 * mix(0.5, detailColor.r, vDetailInfos.y); + surfaceAlbedo = surfaceAlbedo.rgb * detailAlbedo * detailAlbedo; // should be pow(detailAlbedo, 2.2) but detailAlbedo² is close enough and cheaper to compute + #endif + + #ifdef DECAL_AFTER_DETAIL + #include + #endif + + #define CUSTOM_FRAGMENT_UPDATE_ALBEDO + + // According to OpenPBR: + // - for metals, base_weight is a factor to the base_color (F0, thus surfaceAlbedo in + // Babylons.js). + // - for dielectrics, base_weight is a factor to the diffuse BRDF (i.e. it should be + // applied in computeDiffuseLighting), but with the diffuse model *currently* used + // in Babylon.js, factoring it into the surfaceAlbedo is equivalent. + surfaceAlbedo *= baseWeight; + #ifdef BASE_WEIGHT + surfaceAlbedo *= baseWeightTexture.r; + #endif + + // _____________________________ Alpha Information _______________________________ + #ifdef OPACITY + #ifdef OPACITYRGB + alpha = getLuminance(opacityMap.rgb); + #else + alpha *= opacityMap.a; + #endif + + alpha *= vOpacityInfos.y; + #endif + + #if defined(VERTEXALPHA) || defined(INSTANCESCOLOR) && defined(INSTANCES) + alpha *= fragmentInputs.vColor.a; + #endif + + #if !defined(SS_LINKREFRACTIONTOTRANSPARENCY) && !defined(ALPHAFRESNEL) + #ifdef ALPHATEST + #if DEBUGMODE != 88 + if (alpha < ALPHATESTVALUE) { + discard; + } + #endif + + #ifndef ALPHABLEND + // Prevent to blend with the canvas. + alpha = 1.0; + #endif + #endif + #endif + + outParams.surfaceAlbedo = surfaceAlbedo; + outParams.alpha = alpha; + + return outParams; +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx new file mode 100644 index 00000000000..1f45834e4b8 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -0,0 +1,33 @@ +var finalColor: vec4f = vec4f( +#ifndef UNLIT + #ifdef REFLECTION + finalIrradiance + + #endif + #ifdef SPECULARTERM + finalSpecularScaled + + #endif + #ifdef REFLECTION + finalRadianceScaled + + #endif +#endif + finalDiffuse, + alpha); + +// _____________________________ LightMappping _____________________________________ +#ifdef LIGHTMAP + #ifndef LIGHTMAPEXCLUDED + #ifdef USELIGHTMAPASSHADOWMAP + finalColor = vec4f(finalColor.rgb * lightmapColor.rgb, finalColor.a); + #else + finalColor = vec4f(finalColor.rgb + lightmapColor.rgb, finalColor.a); + #endif + #endif +#endif + +// _____________________________ EmissiveLight _____________________________________ +finalColor = vec4f(finalColor.rgb + finalEmission, finalColor.a); + +#define CUSTOM_FRAGMENT_BEFORE_FOG + +// _____________________________ Finally ___________________________________________ +finalColor = max(finalColor, vec4f(0.0)); diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx new file mode 100644 index 00000000000..e3fc7254aa1 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx @@ -0,0 +1,73 @@ +aggShadow = aggShadow / numLights; + +// ______________________________________________________________________________ +// _____________________________ Energy Conservation ___________________________ +// Apply Energy Conservation. +// _____________________________ IBL BRDF + Energy Cons ________________________________ +#if defined(ENVIRONMENTBRDF) + #ifdef MS_BRDF_ENERGY_CONSERVATION + var baseSpecularEnergyConservationFactor: vec3f = getEnergyConservationFactor(vec3f(reflectanceF0), environmentBrdf); + var coloredEnergyConservationFactor: vec3f = getEnergyConservationFactor(specularEnvironmentR0, environmentBrdf); + #endif +#endif + +// _____________________________ Irradiance ______________________________________ +#ifdef REFLECTION + var finalIrradiance: vec3f = reflectionOut.environmentIrradiance; + + // Account for energy loss due to specular reflectance + var baseSpecularEnergy: vec3f = vec3f(baseSpecularEnvironmentReflectance); + #if defined(ENVIRONMENTBRDF) + #ifdef MS_BRDF_ENERGY_CONSERVATION + baseSpecularEnergy *= baseSpecularEnergyConservationFactor; + #endif + #endif + finalIrradiance *= clamp(vec3f(1.0) - baseSpecularEnergy, vec3f(0.0), vec3f(1.0)); + finalIrradiance *= uniforms.vLightingIntensity.z; + finalIrradiance *= surfaceAlbedo.rgb; + finalIrradiance *= aoOut.ambientOcclusionColor; +#endif + +// _____________________________ Specular ________________________________________ +#ifdef SPECULARTERM + var finalSpecular: vec3f = specularBase; + finalSpecular = max(finalSpecular, vec3f(0.0)); + + var finalSpecularScaled: vec3f = finalSpecular * uniforms.vLightingIntensity.x * uniforms.vLightingIntensity.w; + + #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION) + finalSpecularScaled *= coloredEnergyConservationFactor; + #endif +#endif + +// _____________________________ Radiance ________________________________________ +#ifdef REFLECTION + var finalRadiance: vec3f = reflectionOut.environmentRadiance.rgb; + finalRadiance *= colorSpecularEnvironmentReflectance;; + + var finalRadianceScaled: vec3f = finalRadiance * uniforms.vLightingIntensity.z; + + #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION) + finalRadianceScaled *= coloredEnergyConservationFactor; + #endif + +#endif + +// _____________________________ Highlights on Alpha _____________________________ +#ifdef ALPHABLEND + var luminanceOverAlpha: f32 = 0.0; + #if defined(REFLECTION) && defined(RADIANCEOVERALPHA) + luminanceOverAlpha += getLuminance(finalRadianceScaled); + #if defined(CLEARCOAT) + luminanceOverAlpha += getLuminance(clearcoatOut.finalClearCoatRadianceScaled); + #endif + #endif + + #if defined(SPECULARTERM) && defined(SPECULAROVERALPHA) + luminanceOverAlpha += getLuminance(finalSpecularScaled); + #endif + + #if defined(RADIANCEOVERALPHA) || defined(SPECULAROVERALPHA) || defined(CLEARCOATOVERALPHA) + alpha = saturate(alpha + luminanceOverAlpha * luminanceOverAlpha); + #endif +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx new file mode 100644 index 00000000000..e1463573150 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx @@ -0,0 +1,36 @@ +#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + // "Base" specular reflectance is the amount of light prevented from penetrating the diffuse surface by the specular lobe. + // For dielectric materials, this is a greyscale value derived from the IOR and the maximum component of the specular colour. + // For metallic materials, this is vec3(1.0). i.e. no light penetrates to the diffuse surface. + var baseSpecularEnvironmentReflectance: vec3f = getReflectanceFromBRDFWithEnvLookup(vec3f(reflectanceF0), vec3f(reflectivityOut.reflectanceF90), environmentBrdf); + + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + // For OpenPBR, we use a different specular lobe for metallic materials and then blend based on metalness. However, + // to do this correctly, we really need reflectivityOut to contain separate F0 and F90 values for purely dielectric + // and purely metal. Instead, the values are already a mix of dielectric and metallic values. + // So, for intermediate metallic values, the result isn't 100% correct but it seems to work well enough in practice. + // Because specular weight in OpenPBR removes the specular lobe entirely for metals, we do need the actual dielectric + // F0 value to pickup the weight from the dielectric lobe. + let metalEnvironmentReflectance: vec3f = vec3f(reflectivityOut.specularWeight) * getF82Specular(NdotV, reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, reflectivityOut.roughness); + let dielectricEnvironmentReflectance = getReflectanceFromBRDFWithEnvLookup(reflectivityOut.dielectricColorF0, reflectivityOut.colorReflectanceF90, environmentBrdf); + var colorSpecularEnvironmentReflectance: vec3f = mix(dielectricEnvironmentReflectance, metalEnvironmentReflectance, reflectivityOut.metallic); + #else + var colorSpecularEnvironmentReflectance = getReflectanceFromBRDFWithEnvLookup(reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, environmentBrdf); + #endif + + #ifdef RADIANCEOCCLUSION + colorSpecularEnvironmentReflectance *= seo; + #endif + + #ifdef HORIZONOCCLUSION + #ifdef BUMP + #ifdef REFLECTIONMAP_3D + colorSpecularEnvironmentReflectance *= eho; + #endif + #endif + #endif +#else + // Jones implementation of a well balanced fast analytical solution. + var colorSpecularEnvironmentReflectance: vec3f = getReflectanceFromAnalyticalBRDFLookup_Jones(NdotV, reflectivityOut.colorReflectanceF0, reflectivityOut.colorReflectanceF90, sqrt(microSurface)); + var baseSpecularEnvironmentReflectance: vec3f = getReflectanceFromAnalyticalBRDFLookup_Jones(NdotV, vec3f(reflectanceF0), vec3f(reflectivityOut.reflectanceF90), sqrt(microSurface)); +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx new file mode 100644 index 00000000000..d36f6a3935a --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx @@ -0,0 +1,137 @@ +struct reflectivityOutParams +{ + roughness: f32, + diffuseRoughness: f32, + reflectanceF0: f32, + reflectanceF90: vec3f, + colorReflectanceF0: vec3f, + colorReflectanceF90: vec3f, + metallic: f32, + specularWeight: f32, + dielectricColorF0: vec3f, +#if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + ambientOcclusionColor: vec3f, +#endif +#if DEBUGMODE > 0 + #ifdef METALLIC_ROUGHNESS + surfaceMetallicColorMap: vec4f, + #endif + metallicF0: vec3f, +#endif +}; + +#define pbr_inline +fn reflectivityBlock( + reflectanceInfo: vec4f + , surfaceAlbedo: vec3f + , specularColor: vec4f + , baseDiffuseRoughness: f32 +#ifdef BASE_DIFFUSE_ROUGHNESS + , baseDiffuseRoughnessTexture: f32 + , baseDiffuseRoughnessInfos: vec2f +#endif +#ifdef METALLIC_ROUGHNESS + , reflectivityInfos: vec3f + , metallicRoughnessFromTexture: vec4f +#endif +#if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + , ambientOcclusionColorIn: vec3f +#endif +#ifdef DETAIL + , detailColor: vec4f + , vDetailInfos: vec4f +#endif +) -> reflectivityOutParams +{ + var outParams: reflectivityOutParams; + var metallicRoughness: vec2f = reflectanceInfo.rg; + var ior: f32 = reflectanceInfo.b; + #ifdef METALLIC_ROUGHNESS + #if DEBUGMODE > 0 + outParams.surfaceMetallicColorMap = metallicRoughnessFromTexture; + #endif + + #ifdef AOSTOREINMETALMAPRED + var aoStoreInMetalMap: vec3f = vec3f(metallicRoughnessFromTexture.r, metallicRoughnessFromTexture.r, metallicRoughnessFromTexture.r); + outParams.ambientOcclusionColor = mix(ambientOcclusionColorIn, aoStoreInMetalMap, reflectivityInfos.z); + #endif + + metallicRoughness.r *= metallicRoughnessFromTexture.b; + metallicRoughness.g *= metallicRoughnessFromTexture.g; + #endif + + #ifdef DETAIL + var detailRoughness: f32 = mix(0.5, detailColor.b, vDetailInfos.w); + var loLerp: f32 = mix(0., metallicRoughness.g, detailRoughness * 2.); + var hiLerp: f32 = mix(metallicRoughness.g, 1., (detailRoughness - 0.5) * 2.); + metallicRoughness.g = mix(loLerp, hiLerp, step(detailRoughness, 0.5)); + #endif + + #define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS + + outParams.metallic = metallicRoughness.r; + outParams.roughness = metallicRoughness.g; + outParams.specularWeight = specularColor.a; + const outsideIOR: f32 = 1.0; + let dielectricF0: f32 = pow((ior - outsideIOR) / (ior + outsideIOR), 2.0) * outParams.specularWeight; + + #if DEBUGMODE > 0 + outParams.metallicF0 = dielectricF0 * specularColor.rgb; + #endif + + // Compute non-coloured reflectance. + // reflectanceF0 is the non-coloured reflectance used for blending between the diffuse and specular components. + // It represents the total percentage of light reflected by the specular lobe at normal incidence. + // In glTF's material model, the F0 value is multiplied by the maximum component of the specular colour. + #if DIELECTRIC_SPECULAR_MODEL == DIELECTRIC_SPECULAR_MODEL_GLTF + let maxF0: f32 = max(specularColor.r, max(specularColor.g, specularColor.b)); + outParams.reflectanceF0 = mix(dielectricF0 * maxF0, 1.0f, outParams.metallic); + #else + outParams.reflectanceF0 = mix(dielectricF0, 1.0, outParams.metallic); + #endif + + // Scale the reflectanceF90 by the IOR for values less than 1.5. + // This is an empirical hack to account for the fact that Schlick is tuned for IOR = 1.5 + // and an IOR of 1.0 should result in no visible glancing specular. + var f90Scale: f32 = clamp(2.0 * (ior - 1.0), 0.0, 1.0); + outParams.reflectanceF90 = vec3(mix( + outParams.specularWeight * f90Scale, 1.0, outParams.metallic)); + + // Compute the coloured F0 reflectance. + // The coloured reflectance is the percentage of light reflected by the specular lobe at normal incidence. + // In glTF and OpenPBR, it is not the same thing as the percentage of light blocked from penetrating + // down to the diffuse lobe. The non-coloured F0 will be used for this (see below). + outParams.dielectricColorF0 = vec3f(dielectricF0 * specularColor.rgb); + var metallicColorF0: vec3f = surfaceAlbedo.rgb; + outParams.colorReflectanceF0 = mix(outParams.dielectricColorF0, metallicColorF0, outParams.metallic); + + // Now, compute the coloured reflectance at glancing angles based on the specular model. + #if (DIELECTRIC_SPECULAR_MODEL == DIELECTRIC_SPECULAR_MODEL_OPENPBR) + // In OpenPBR, the F90 is coloured using the specular colour for dielectrics. + let dielectricColorF90 + : vec3f = specularColor.rgb * + vec3f(outParams.specularWeight * f90Scale); + #else + // In glTF, the F90 is white for dielectrics. + let dielectricColorF90 + : vec3f = vec3f(outParams.specularWeight * f90Scale); + #endif + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + // In OpenPBR, we use the "F82" model for conductors. + // We'll use the F90 value to hold the F82 tint which will be used in the computation later. + let conductorColorF90: vec3f = specularColor.rgb; + #else + // In glTF, the F90 colour for metals is white. + let conductorColorF90: vec3f = vec3f(1.0f); + #endif + outParams.colorReflectanceF90 = mix(dielectricColorF90, conductorColorF90, outParams.metallic); + + var diffuseRoughness: f32 = baseDiffuseRoughness; +#ifdef BASE_DIFFUSE_ROUGHNESS + diffuseRoughness *= baseDiffuseRoughnessTexture * baseDiffuseRoughnessInfos.y; +#endif + + outParams.diffuseRoughness = diffuseRoughness; + + return outParams; +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx new file mode 100644 index 00000000000..78bf8a3c071 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -0,0 +1,69 @@ +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_SAMPLERNAME_,baseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_SAMPLERNAME_,baseDiffuseRoughness) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_SAMPLERNAME_,baseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight,_SAMPLERNAME_,specularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor,_SAMPLERNAME_,specularColor) +#include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) +#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) + +#include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) + + +// Reflection +#ifdef REFLECTION + #ifdef REFLECTIONMAP_3D + var reflectionSamplerSampler: sampler; + var reflectionSampler: texture_cube; + + #ifdef LODBASEDMICROSFURACE + #else + var reflectionLowSamplerSampler: sampler; + var reflectionLowSampler: texture_cube; + var reflectionHighSamplerSampler: sampler; + var reflectionHighSampler: texture_cube; + #endif + + #ifdef USEIRRADIANCEMAP + var irradianceSamplerSampler: sampler; + var irradianceSampler: texture_cube; + #endif + #else + + var reflectionSamplerSampler: sampler; + var reflectionSampler: texture_2d; + + #ifdef LODBASEDMICROSFURACE + #else + var reflectionLowSamplerSampler: sampler; + var reflectionLowSampler: texture_2d; + var reflectionHighSamplerSampler: sampler; + var reflectionHighSampler: texture_2d; + #endif + + #ifdef USEIRRADIANCEMAP + var irradianceSamplerSampler: sampler; + var irradianceSampler: texture_2d; + #endif + #endif + + #ifdef REFLECTIONMAP_SKYBOX + varying vPositionUVW: vec3f; + #else + #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) + varying vDirectionW: vec3f; + #endif + #endif +#endif + +#ifdef ENVIRONMENTBRDF + var environmentBrdfSamplerSampler: sampler; + var environmentBrdfSampler: texture_2d; +#endif + +#ifdef IBL_CDF_FILTERING + var icdfSamplerSampler: sampler; + var icdfSampler: texture_2d; +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx index 58f5fc763e1..e993e06e80e 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx @@ -9,7 +9,7 @@ #define CONDUCTOR_SPECULAR_MODEL_GLTF 0 #define CONDUCTOR_SPECULAR_MODEL_OPENPBR 1 -#ifndef PBR_VERTEX_SHADER +#if !defined(PBR_VERTEX_SHADER) && !defined(OPENPBR_VERTEX_SHADER) // ______________________________________________________________________ // diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx index e0922402feb..6eacae512da 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx @@ -7,10 +7,6 @@ uniform vEmissiveInfos: vec2f; uniform vLightmapInfos: vec2f; uniform vReflectivityInfos: vec3f; uniform vMicroSurfaceSamplerInfos: vec2f; -uniform vReflectionInfos: vec2f; -uniform vReflectionFilteringInfo: vec2f; -uniform vReflectionPosition: vec3f; -uniform vReflectionSize: vec3f; uniform vBumpInfos: vec3f; uniform albedoMatrix: mat4x4f; uniform baseWeightMatrix: mat4x4f; @@ -23,14 +19,10 @@ uniform reflectivityMatrix: mat4x4f; uniform microSurfaceSamplerMatrix: mat4x4f; uniform bumpMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; -uniform reflectionMatrix: mat4x4f; -uniform vReflectionColor: vec3f; uniform vAlbedoColor: vec4f; uniform baseWeight: f32; uniform baseDiffuseRoughness: f32; uniform vLightingIntensity: vec4f; -uniform vReflectionMicrosurfaceInfos: vec3f; -uniform vReflectionDominantDirection: vec3f; uniform pointSize: f32; uniform vReflectivityColor: vec4f; uniform vEmissiveColor: vec3f; @@ -43,6 +35,16 @@ uniform vMetallicReflectanceInfos: vec2f; uniform metallicReflectanceMatrix: mat4x4f; uniform vReflectanceInfos: vec2f; uniform reflectanceMatrix: mat4x4f; +uniform cameraInfo: vec4f; + +uniform vReflectionInfos: vec2f; +uniform reflectionMatrix: mat4x4f; +uniform vReflectionMicrosurfaceInfos: vec3f; +uniform vReflectionPosition: vec3f; +uniform vReflectionSize: vec3f; +uniform vReflectionFilteringInfo: vec2f; +uniform vReflectionDominantDirection: vec3f; +uniform vReflectionColor: vec3f; uniform vSphericalL00: vec3f; uniform vSphericalL1_1: vec3f; @@ -64,8 +66,6 @@ uniform vSphericalXY: vec3f; uniform vSphericalYZ: vec3f; uniform vSphericalZX: vec3f; -uniform cameraInfo: vec4f; - #define ADDITIONAL_UBO_DECLARATION diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx new file mode 100644 index 00000000000..3e29dd60f18 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -0,0 +1,345 @@ +#define OPENPBR_FRAGMENT_SHADER + +#define CUSTOM_FRAGMENT_BEGIN + +#include[SCENE_MRT_COUNT] +#include + +// Forces linear space for image processing +#ifndef FROMLINEARSPACE + #define FROMLINEARSPACE +#endif + +// Declaration +#include + +#include +#include[0..maxSimultaneousLights] +#include +#include +#include +#include +#include + +// Helper Functions +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef REFLECTION + #include +#endif + +#define CUSTOM_FRAGMENT_DEFINITIONS + +#include +#include +#include +#include +#include + +// _____________________________ MAIN FUNCTION ____________________________ +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + + #define CUSTOM_FRAGMENT_MAIN_BEGIN + + #include + + // _____________________________ Geometry Information ____________________________ + #include + + #include + + #include + + // _____________________________ Albedo & Opacity ______________________________ + var albedoOpacityOut: albedoOpacityOutParams; + +#ifdef BASE_COLOR + var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, fragmentInputs.vBaseColorUV + uvOffset); +#endif + +#ifdef BASE_WEIGHT + var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, fragmentInputs.vBaseWeightUV + uvOffset); +#endif + +#ifdef OPACITY + var opacityMap: vec4f = textureSample(opacitySampler, opacitySamplerSampler, fragmentInputs.vOpacityUV + uvOffset); +#endif + +#ifdef DECAL + var decalColor: vec4f = textureSample(decalSampler, decalSamplerSampler, fragmentInputs.vDecalUV + uvOffset); +#endif + + albedoOpacityOut = albedoOpacityBlock( + uniforms.vBaseColor + #ifdef BASE_COLOR + , baseColorFromTexture + , uniforms.vBaseColorInfos + #endif + , uniforms.baseWeight + #ifdef BASE_WEIGHT + , baseWeightFromTexture + , uniforms.vBaseWeightInfos + #endif + #ifdef OPACITY + , opacityMap + , uniforms.vOpacityInfos + #endif + #ifdef DETAIL + , detailColor + , uniforms.vDetailInfos + #endif + #ifdef DECAL + , decalColor + , uniforms.vDecalInfos + #endif + ); + + var surfaceAlbedo: vec3f = albedoOpacityOut.surfaceAlbedo; + var alpha: f32 = albedoOpacityOut.alpha; + + #define CUSTOM_FRAGMENT_UPDATE_ALPHA + + #include + + #define CUSTOM_FRAGMENT_BEFORE_LIGHTS + + // _____________________________ AO _______________________________ + var aoOut: ambientOcclusionOutParams; + +#ifdef AMBIENT_OCCLUSION + var ambientOcclusionFromTexture: vec3f = textureSample(ambientOcclusionSampler, ambientOcclusionSamplerSampler, fragmentInputs.vAmbientOcclusionUV + uvOffset).rgb; +#endif + + aoOut = ambientOcclusionBlock( + #ifdef AMBIENT_OCCLUSION + ambientOcclusionFromTexture, + uniforms.vAmbientOcclusionInfos + #endif + ); + + #include + +#ifdef UNLIT + var diffuseBase: vec3f = vec3f(1., 1., 1.); +#else + + // _____________________________ Reflectivity _______________________________ + var baseColor: vec3f = surfaceAlbedo; + + var reflectivityOut: reflectivityOutParams; + +#ifdef METALLIC_ROUGHNESS + var metallicRoughnessFromTexture: vec4f = textureSample(baseMetalRoughSampler, baseMetalRoughSamplerSampler, fragmentInputs.vBaseMetalRoughUV + uvOffset); +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + var baseDiffuseRoughnessFromTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, fragmentInputs.vBaseDiffuseRoughnessUV + uvOffset).x; +#endif + +var specularColor: vec4f = uniforms.vSpecularColor; +#ifdef SPECULAR_COLOR + var specularColorFromTexture: vec4f = textureSample(specularColorSampler, specularColorSamplerSampler, fragmentInputs.vSpecularColorUV + uvOffset); + #ifdef SPECULAR_COLOR_GAMMA + specularColorFromTexture = toLinearSpaceVec4(specularColorFromTexture); + #endif + + specularColor = vec4f(specularColor.rgb * specularColorFromTexture.rgb, specularColor.a); +#endif +#ifdef SPECULAR_WEIGHT + var specularWeightFromTexture: vec4f = textureSample(specularWeightSampler, specularWeightSamplerSampler, fragmentInputs.vSpecularWeightUV + uvOffset); + #ifdef SPECULAR_WEIGHT_GAMMA + specularWeightFromTexture = toLinearSpaceVec4(specularWeightFromTexture); + #endif + + // If loaded from a glTF, the specular_weight is stored in the alpha channel. + // Otherwise, it's expected to just be a greyscale texture. + #ifdef SPECULAR_WEIGHT_USE_ALPHA_ONLY + specularColor.a *= specularWeightFromTexture.a; + #else + specularColor = vec4f(specularColor.rgb * specularWeightFromTexture.rgb, specularColor.a); + #endif +#endif + + reflectivityOut = reflectivityBlock( + uniforms.vReflectanceInfo + , surfaceAlbedo + , specularColor + , uniforms.vBaseDiffuseRoughness + #ifdef BASE_DIFFUSE_ROUGHNESS + , baseDiffuseRoughnessFromTexture + , uniforms.vBaseDiffuseRoughnessInfos + #endif + #ifdef METALLIC_ROUGHNESS + , vec3f(uniforms.vBaseMetalRoughInfos, 1.0f) + , metallicRoughnessFromTexture + #endif + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + , aoOut.ambientOcclusionColor + #endif + #ifdef DETAIL + , detailColor + , uniforms.vDetailInfos + #endif + ); + + var roughness: f32 = reflectivityOut.roughness; + var diffuseRoughness: f32 = reflectivityOut.diffuseRoughness; + + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) + aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; + #endif + + // _____________________________ Compute Geometry info _________________________________ + #include + + // _____________________________ Reflection Info _______________________________________ + #ifdef REFLECTION + var reflectionOut: reflectionOutParams; + + #ifndef USE_CUSTOM_REFLECTION + reflectionOut = reflectionBlock( + fragmentInputs.vPositionW + , normalW + , alphaG + , uniforms.vReflectionMicrosurfaceInfos + , uniforms.vReflectionInfos + , uniforms.vReflectionColor + #ifdef ANISOTROPIC + , anisotropicOut + #endif + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , NdotVUnclamped + #endif + , reflectionSampler + , reflectionSamplerSampler + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + , fragmentInputs.vEnvironmentIrradiance + #endif + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + , uniforms.reflectionMatrix + #endif + #ifdef USEIRRADIANCEMAP + , irradianceSampler + , irradianceSamplerSampler + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + , uniforms.vReflectionDominantDirection + #endif + #endif + #ifndef LODBASEDMICROSFURACE + , reflectionLowSampler + , reflectionLowSamplerSampler + , reflectionHighSampler + , reflectionHighSamplerSampler + #endif + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + , icdfSamplerSampler + #endif + #endif + , viewDirectionW + , diffuseRoughness + , surfaceAlbedo + ); + #else + #define CUSTOM_REFLECTION + #endif + #endif + + // ___________________ Compute Reflectance aka R0 F0 info _________________________ + var reflectanceF0: f32 = reflectivityOut.reflectanceF0; + var specularEnvironmentR0: vec3f = reflectivityOut.colorReflectanceF0; + var specularEnvironmentR90: vec3f = reflectivityOut.colorReflectanceF90; + + // _________________________ Specular Environment Reflectance __________________________ + #include + + // _____________________________ Direct Lighting Info __________________________________ + #include + // TODO: lightFragment references cloatcoatOut, subsurfaceOut, etc. + // lightFragment shouldn't know what layer it's working on. + // Instead, we should define values for lightFragment to use here, defining + // conditions like F0, F90, etc. + // Or we could convert lightFragment to be a function that returns the diffuse + // or specular contribution, given the reflectance inputs? + // e.g. lighting contributions from clearcoat, subsurface, base layer, etc. need + // to be computed separately. + // #include[0..maxSimultaneousLights] + + // _____________________________ Compute Final Lit Components ________________________ + #include +#endif // UNLIT + + // _____________________________ Diffuse ________________________________________ + var finalDiffuse: vec3f = diffuseBase; + finalDiffuse *= surfaceAlbedo; + finalDiffuse = max(finalDiffuse, vec3f(0.0)); + finalDiffuse *= uniforms.vLightingIntensity.x; + + // _____________________________ Emissive ________________________________________ + var finalEmission: vec3f = uniforms.vEmissionColor; + #ifdef EMISSION + var emissionColorTex: vec3f = textureSample(emissionSampler, emissionSamplerSampler, fragmentInputs.vEmissionUV + uvOffset).rgb; + #ifdef EMISSION_GAMMA + finalEmission *= toLinearSpaceVec3(emissionColorTex.rgb); + #else + finalEmission *= emissionColorTex.rgb; + #endif + finalEmission *= uniforms.vEmissionInfos.y; + #endif + finalEmission *= uniforms.vLightingIntensity.y; + + // ______________________________ Ambient ________________________________________ + #ifdef AMBIENT_OCCLUSION + finalDiffuse *= mix( vec3f(1.), aoOut.ambientOcclusionColor, 1.0 - uniforms.vAmbientOcclusionInfos.y); + #endif + + #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION + + #include + + #include + #include(color, finalColor) + #include + + #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR + +#ifdef PREPASS + #include +#endif + +#if !defined(PREPASS) && !defined(ORDER_INDEPENDENT_TRANSPARENCY) + fragmentOutputs.color = finalColor; +#endif + + #include + +#if ORDER_INDEPENDENT_TRANSPARENCY + if (fragDepth == nearestDepth) { + fragmentOutputs.frontColor = vec4f(fragmentOutputs.frontColor.rgb + finalColor.rgb * finalColor.a * alphaMultiplier, 1.0 - alphaMultiplier * (1.0 - finalColor.a)); + } else { + fragmentOutputs.backColor += finalColor; + } +#endif + + #include + + #define CUSTOM_FRAGMENT_MAIN_END + +} diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx new file mode 100644 index 00000000000..8daa3da7b79 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -0,0 +1,238 @@ +#define OPENPBR_VERTEX_SHADER + +#include + +#define CUSTOM_VERTEX_BEGIN + +// Attributes +attribute position: vec3f; +#ifdef NORMAL +attribute normal: vec3f; +#endif +#ifdef TANGENT +attribute tangent: vec4f; +#endif +#ifdef UV1 +attribute uv: vec2f; +#endif +#include[2..7] +#include[1..7] +#ifdef VERTEXCOLOR +attribute color: vec4f; +#endif + +#include +#include +#include +#include + +#include +#include + +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,Albedo) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) +#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) + +#include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) +#include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) + +// Output +varying vPositionW: vec3f; +#if DEBUGMODE > 0 + varying vClipSpacePosition: vec4f; +#endif +#ifdef NORMAL + varying vNormalW: vec3f; + #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) + varying vEnvironmentIrradiance: vec3f; + + #include + #endif +#endif + +#if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) +varying vColor: vec4f; +#endif + +#include +#include +#include +#include[0..maxSimultaneousLights] + +#include +#include[0..maxSimultaneousMorphTargets] + +#ifdef REFLECTIONMAP_SKYBOX +varying vPositionUVW: vec3f; +#endif + +#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) +varying vDirectionW: vec3f; +#endif + +#include +#define CUSTOM_VERTEX_DEFINITIONS + +@vertex +fn main(input : VertexInputs) -> FragmentInputs { + + #define CUSTOM_VERTEX_MAIN_BEGIN + + var positionUpdated: vec3f = vertexInputs.position; +#ifdef NORMAL + var normalUpdated: vec3f = vertexInputs.normal; +#endif +#ifdef TANGENT + var tangentUpdated: vec4f = vertexInputs.tangent; +#endif +#ifdef UV1 + var uvUpdated: vec2f = vertexInputs.uv; +#endif +#ifdef UV2 + var uv2Updated: vec2f = vertexInputs.uv2; +#endif +#ifdef VERTEXCOLOR + var colorUpdated: vec4f = vertexInputs.color; +#endif + +#include +#include[0..maxSimultaneousMorphTargets] + +#ifdef REFLECTIONMAP_SKYBOX + vertexOutputs.vPositionUVW = positionUpdated; +#endif + +#define CUSTOM_VERTEX_UPDATE_POSITION + +#define CUSTOM_VERTEX_UPDATE_NORMAL + +#include + +#if defined(PREPASS) && ((defined(PREPASS_VELOCITY) || defined(PREPASS_VELOCITY_LINEAR)) && !defined(BONES_VELOCITY_ENABLED) + // Compute velocity before bones computation + vertexOutputs.vCurrentPosition = scene.viewProjection * finalWorld * vec4f(positionUpdated, 1.0); + vertexOutputs.vPreviousPosition = uniforms.previousViewProjection * finalPreviousWorld * vec4f(positionUpdated, 1.0); +#endif + +#include +#include + + var worldPos: vec4f = finalWorld * vec4f(positionUpdated, 1.0); + vertexOutputs.vPositionW = worldPos.xyz; + +#ifdef PREPASS + #include +#endif + +#ifdef NORMAL + var normalWorld: mat3x3f = mat3x3f(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz); + + #if defined(INSTANCES) && defined(THIN_INSTANCES) + vertexOutputs.vNormalW = normalUpdated / vec3f(dot(normalWorld[0], normalWorld[0]), dot(normalWorld[1], normalWorld[1]), dot(normalWorld[2], normalWorld[2])); + vertexOutputs.vNormalW = normalize(normalWorld * vertexOutputs.vNormalW); + #else + #ifdef NONUNIFORMSCALING + normalWorld = transposeMat3(inverseMat3(normalWorld)); + #endif + + vertexOutputs.vNormalW = normalize(normalWorld * normalUpdated); + #endif + + #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) + #if BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LAMBERT && BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LEGACY + // Bend the normal towards the viewer based on the diffuse roughness + var viewDirectionW: vec3f = normalize(scene.vEyePosition.xyz - vertexOutputs.vPositionW); + var NdotV: f32 = max(dot(vertexOutputs.vNormalW, viewDirectionW), 0.0); + var roughNormal: vec3f = mix(vertexOutputs.vNormalW, viewDirectionW, (0.5 * (1.0 - NdotV)) * uniforms.vBaseDiffuseRoughness); + var reflectionVector: vec3f = (uniforms.reflectionMatrix * vec4f(roughNormal, 0)).xyz; + #else + var reflectionVector: vec3f = (uniforms.reflectionMatrix * vec4f(vertexOutputs.vNormalW, 0)).xyz; + #endif + #ifdef REFLECTIONMAP_OPPOSITEZ + reflectionVector.z *= -1.0; + #endif + + vertexOutputs.vEnvironmentIrradiance = computeEnvironmentIrradiance(reflectionVector); + #endif +#endif + +#define CUSTOM_VERTEX_UPDATE_WORLDPOS + +#ifdef MULTIVIEW + if (gl_ViewID_OVR == 0u) { + vertexOutputs.position = scene.viewProjection * worldPos; + } else { + vertexOutputs.position = scene.viewProjectionR * worldPos; + } +#else + vertexOutputs.position = scene.viewProjection * worldPos; +#endif + +#if DEBUGMODE > 0 + vertexOutputs.vClipSpacePosition = vertexOutputs.position; +#endif + +#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED) + vertexOutputs.vDirectionW = normalize((finalWorld * vec4f(positionUpdated, 0.0)).xyz); +#endif + + // Texture coordinates +#ifndef UV1 + var uvUpdated: vec2f = vec2f(0., 0.); +#endif +#ifdef MAINUV1 + vertexOutputs.vMainUV1 = uvUpdated; +#endif +#ifndef UV2 + var uv2Updated: vec2f = vec2f(0., 0.); +#endif +#ifdef MAINUV2 + vertexOutputs.vMainUV2 = uv2Updated; +#endif + + #include[3..7] + + #include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor,_MATRIXNAME_,baseColor,_INFONAME_,BaseColorInfos.x) + #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_MATRIXNAME_,baseWeight,_INFONAME_,BaseWeightInfos.x) + #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_MATRIXNAME_,baseDiffuseRoughness,_INFONAME_,BaseDiffuseRoughnessInfos.x) + #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_MATRIXNAME_,baseMetalRough,_INFONAME_,BaseMetalRoughInfos.x) + #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight,_MATRIXNAME_,specularWeight,_INFONAME_,SpecularWeightInfos.x) + #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor,_MATRIXNAME_,specularColor,_INFONAME_,SpecularColorInfos.x) + #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) + #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) + + #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_MATRIXNAME_,ambientOcclusion,_INFONAME_,AmbientOcclusionInfos.x) + #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) + #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) + #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) + #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) + + // TBN +#include + + // Clip plane +#include + + // Fog +#include + + // Shadows +#include[0..maxSimultaneousLights] + + // Vertex color +#include + + // Log. depth +#include + +#define CUSTOM_VERTEX_MAIN_END + +} \ No newline at end of file diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index d67eb582f9c..4e3e537d2f2 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx @@ -117,6 +117,7 @@ import { Tags } from "core/Misc/tags"; import { LineContainerComponent } from "shared-ui-components/lines/lineContainerComponent"; import type { RectAreaLight } from "core/Lights/rectAreaLight"; import { FluentToolWrapper } from "shared-ui-components/fluent/hoc/fluentToolWrapper"; +import type { OpenPBRMaterial } from "core/Materials"; export class PropertyGridTabComponent extends PaneComponent { private _timerIntervalId: number; @@ -396,6 +397,17 @@ export class PropertyGridTabComponent extends PaneComponent { onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> ); + } else if (className === "OpenPBRMaterial") { + const material = entity as OpenPBRMaterial; + return ( + + ); } if (className === "PBRMetallicRoughnessMaterial") { diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx index 32df71c593e..b28df370c69 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { Observable } from "core/Misc/observable"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import { Constants } from "core/Engines/constants"; import type { PropertyChangedEvent } from "../../../../propertyChangedEvent"; @@ -19,10 +19,11 @@ import { Vector2LineComponent } from "shared-ui-components/lines/vector2LineComp import "core/Materials/material.decalMap"; import "core/Rendering/prePassRendererSceneComponent"; import "core/Rendering/subSurfaceSceneComponent"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; interface IPBRMaterialPropertyGridComponentProps { globalState: GlobalState; - material: PBRMaterial; + material: PBRMaterial | OpenPBRMaterial; lockObject: LockObject; onSelectionChangedObservable?: Observable; onPropertyChangedObservable?: Observable; @@ -46,14 +47,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component - + {material instanceof PBRMaterial && ( + + )} - + {material instanceof PBRMaterial && ( + + )} - - - + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} - (material.detailMap.texture = texture)} - onTextureRemoved={() => (material.detailMap.texture = null)} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} - /> - - - {material.decalMap && ( + {material instanceof PBRMaterial && ( + <> + (material.detailMap.texture = texture)} + onTextureRemoved={() => (material.detailMap.texture = null)} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} + /> + + + + )} + {material instanceof PBRMaterial && material.decalMap && ( - (material.metallicReflectanceTexture = texture)} - onTextureRemoved={() => (material.metallicReflectanceTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.reflectanceTexture = texture)} - onTextureRemoved={() => (material.reflectanceTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> + {material instanceof PBRMaterial && ( + (material.metallicReflectanceTexture = texture)} + onTextureRemoved={() => (material.metallicReflectanceTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + )} + {material instanceof PBRMaterial && ( + (material.reflectanceTexture = texture)} + onTextureRemoved={() => (material.reflectanceTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + )} - - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.clearCoat.isEnabled && ( -
- - - + {material instanceof PBRMaterial && ( + <> + this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - (material.clearCoat.texture = texture)} - onTextureRemoved={() => (material.clearCoat.texture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.clearCoat.textureRoughness = texture)} - onTextureRemoved={() => (material.clearCoat.textureRoughness = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.clearCoat.bumpTexture = texture)} - onTextureRemoved={() => (material.clearCoat.bumpTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - {material.clearCoat.bumpTexture && ( - + {material.clearCoat.isEnabled && ( +
+ + + + + (material.clearCoat.texture = texture)} + onTextureRemoved={() => (material.clearCoat.texture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + (material.clearCoat.textureRoughness = texture)} + onTextureRemoved={() => (material.clearCoat.textureRoughness = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + (material.clearCoat.bumpTexture = texture)} + onTextureRemoved={() => (material.clearCoat.bumpTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + {material.clearCoat.bumpTexture && ( + + )} + + + {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( + + )} + {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( + + )} + {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( + + )} + {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( + (material.clearCoat.tintTexture = texture)} + onTextureRemoved={() => (material.clearCoat.tintTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + )} +
)} +
+ - - {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( - - )} - {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( - - )} - {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( - - )} - {material.clearCoat.isEnabled && material.clearCoat.isTintEnabled && ( - (material.clearCoat.tintTexture = texture)} - onTextureRemoved={() => (material.clearCoat.tintTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - )} -
- )} -
- - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.iridescence.isEnabled && ( -
- - - - this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - (material.iridescence.texture = texture)} - onTextureRemoved={() => (material.iridescence.texture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.iridescence.thicknessTexture = texture)} - onTextureRemoved={() => (material.iridescence.thicknessTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> -
- )} -
- - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.anisotropy.isEnabled && ( -
+ {material.iridescence.isEnabled && ( +
+ + + + + (material.iridescence.texture = texture)} + onTextureRemoved={() => (material.iridescence.texture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + (material.iridescence.thicknessTexture = texture)} + onTextureRemoved={() => (material.iridescence.thicknessTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> +
+ )} + + this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - - - (material.anisotropy.texture = texture)} - onTextureRemoved={() => (material.anisotropy.texture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> -
- )} -
- - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.sheen.isEnabled && ( -
- - - - (material.sheen.texture = texture)} - onTextureRemoved={() => (material.sheen.texture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.sheen.textureRoughness = texture)} - onTextureRemoved={() => (material.sheen.textureRoughness = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - - {(material.sheen as any)._useRoughness && ( - + {material.anisotropy.isEnabled && ( +
+ this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + + + (material.anisotropy.texture = texture)} + onTextureRemoved={() => (material.anisotropy.texture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> +
)} + + - this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> -
- )} -
- - (material.subSurface.thicknessTexture = texture)} - onTextureRemoved={() => (material.subSurface.thicknessTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - - - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - + {material.sheen.isEnabled && ( +
+ + + + (material.sheen.texture = texture)} + onTextureRemoved={() => (material.sheen.texture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + (material.sheen.textureRoughness = texture)} + onTextureRemoved={() => (material.sheen.textureRoughness = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + + {(material.sheen as any)._useRoughness && ( + + )} + + +
+ )} +
- this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {(material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration && ( -
- -
- )} - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.subSurface.isRefractionEnabled && ( -
- + (material.subSurface.refractionIntensityTexture = texture)} - onTextureRemoved={() => (material.subSurface.refractionIntensityTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - (material.subSurface.refractionTexture = texture)} - onTextureRemoved={() => (material.subSurface.refractionTexture = null)} + label="Thickness" + texture={material.subSurface.thicknessTexture} + onTextureCreated={(texture) => (material.subSurface.thicknessTexture = texture)} + onTextureRemoved={() => (material.subSurface.thicknessTexture = null)} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} /> this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> -
- )} - - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.subSurface.isDispersionEnabled && ( -
- this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> -
- )} - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - {material.subSurface.isTranslucencyEnabled && ( -
- - (material.subSurface.translucencyIntensityTexture = texture)} - onTextureRemoved={() => (material.subSurface.translucencyIntensityTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} - isLinear={true} /> + {(material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration && ( +
+ +
+ )} this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - + + (material.subSurface.refractionIntensityTexture = texture)} + onTextureRemoved={() => (material.subSurface.refractionIntensityTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + (material.subSurface.refractionTexture = texture)} + onTextureRemoved={() => (material.subSurface.refractionTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + + + + +
+ )} + + this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} - isLinear={true} /> - (material.subSurface.translucencyColorTexture = texture)} - onTextureRemoved={() => (material.subSurface.translucencyColorTexture = null)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + {material.subSurface.isDispersionEnabled && ( +
+ +
+ )} + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - - )} - + {material.subSurface.isTranslucencyEnabled && ( +
+ + (material.subSurface.translucencyIntensityTexture = texture)} + onTextureRemoved={() => (material.subSurface.translucencyIntensityTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + + + + (material.subSurface.translucencyColorTexture = texture)} + onTextureRemoved={() => (material.subSurface.translucencyColorTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> +
+ )} + + + )} )} - {material.clearCoat.texture && ( + {material instanceof PBRMaterial && material.clearCoat.texture && ( )} - {material.clearCoat.bumpTexture && ( + {material instanceof PBRMaterial && material.clearCoat.bumpTexture && ( )} - {material.clearCoat.tintTexture && false /* level is not used for the clear coat tint texture */ && ( + {material instanceof PBRMaterial && material.clearCoat.tintTexture && false /* level is not used for the clear coat tint texture */ && ( )} - {material.anisotropy.texture && ( + {material instanceof PBRMaterial && material.anisotropy.texture && ( )} - {material.sheen.texture && ( + {material instanceof PBRMaterial && material.sheen.texture && ( )} - {material.subSurface.thicknessTexture && ( + {material instanceof PBRMaterial && material.subSurface.thicknessTexture && ( )} - {material.subSurface.refractionTexture && ( + {material instanceof PBRMaterial && material.subSurface.refractionTexture && ( )} - {material.detailMap.isEnabled && ( + {material instanceof PBRMaterial && material.detailMap.isEnabled && ( <> - - - + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> + {material instanceof PBRMaterial && ( + <> + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + + )} - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} - /> + {material instanceof PBRMaterial && ( + <> + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + + )} diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.ts index 2ded7721f72..6fad1d1968f 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -74,13 +75,15 @@ export class EXT_materials_diffuse_roughness implements IGLTFLoaderExtension { // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax private _loadDiffuseRoughnessPropertiesAsync(context: string, properties: IEXTMaterialsDiffuseRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - babylonMaterial.brdf.baseDiffuseModel = Constants.MATERIAL_DIFFUSE_MODEL_E_OREN_NAYAR; + if (babylonMaterial instanceof PBRMaterial) { + babylonMaterial.brdf.baseDiffuseModel = Constants.MATERIAL_DIFFUSE_MODEL_E_OREN_NAYAR; + } if (properties.diffuseRoughnessFactor != undefined) { babylonMaterial.baseDiffuseRoughness = properties.diffuseRoughnessFactor; diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_anisotropy.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_anisotropy.ts index c425c295da5..9c3e82ddad3 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_anisotropy.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_anisotropy.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -21,6 +22,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy) */ @@ -60,33 +63,40 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); await Promise.all(promises); }); } private async _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsAnisotropy, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - babylonMaterial.anisotropy.isEnabled = true; + (babylonMaterial as PBRMaterial).anisotropy.isEnabled = true; - babylonMaterial.anisotropy.intensity = properties.anisotropyStrength ?? 0; - babylonMaterial.anisotropy.angle = properties.anisotropyRotation ?? 0; + (babylonMaterial as PBRMaterial).anisotropy.intensity = properties.anisotropyStrength ?? 0; + (babylonMaterial as PBRMaterial).anisotropy.angle = properties.anisotropyRotation ?? 0; if (properties.anisotropyTexture) { (properties.anisotropyTexture as ITextureInfo).nonColorData = true; promises.push( this._loader.loadTextureInfoAsync(`${context}/anisotropyTexture`, properties.anisotropyTexture, (texture) => { texture.name = `${babylonMaterial.name} (Anisotropy Intensity)`; - babylonMaterial.anisotropy.texture = texture; + (babylonMaterial as PBRMaterial).anisotropy.texture = texture; }) ); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts index bc394cd1040..22d4b3e84d5 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts @@ -1,6 +1,8 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; +import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -21,6 +23,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md) * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8) @@ -61,46 +65,58 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + if (!(babylonMaterial instanceof PBRMaterialClass)) { + throw new Error(`${context}: Material type not supported`); + } + promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); await Promise.all(promises); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadClearCoatPropertiesAsync(context: string, properties: IKHRMaterialsClearcoat, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadClearCoatPropertiesAsync(context: string, properties: IKHRMaterialsClearcoat, babylonMaterial: Material, useOpenPBR: boolean = false): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - - babylonMaterial.clearCoat.isEnabled = true; - babylonMaterial.clearCoat.useRoughnessFromMainTexture = false; - babylonMaterial.clearCoat.remapF0OnInterfaceChange = false; + let coatRoughness = 0; + let coatWeight = 0; + let coatWeightTexture: Nullable = null; + let coatRoughnessTexture: Nullable = null; + let coatNormalTexture: Nullable = null; + let coatNormalTextureScale = 1; if (properties.clearcoatFactor != undefined) { - babylonMaterial.clearCoat.intensity = properties.clearcoatFactor; + coatWeight = properties.clearcoatFactor; } else { - babylonMaterial.clearCoat.intensity = 0; + coatWeight = 0; } if (properties.clearcoatTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatTexture`, properties.clearcoatTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat)`; - babylonMaterial.clearCoat.texture = texture; + coatWeightTexture = texture; }) ); } if (properties.clearcoatRoughnessFactor != undefined) { - babylonMaterial.clearCoat.roughness = properties.clearcoatRoughnessFactor; + coatRoughness = properties.clearcoatRoughnessFactor; } else { - babylonMaterial.clearCoat.roughness = 0; + coatRoughness = 0; } if (properties.clearcoatRoughnessTexture) { @@ -108,7 +124,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatRoughnessTexture`, properties.clearcoatRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat Roughness)`; - babylonMaterial.clearCoat.textureRoughness = texture; + coatRoughnessTexture = texture; }) ); } @@ -118,19 +134,37 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatNormalTexture`, properties.clearcoatNormalTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat Normal)`; - babylonMaterial.clearCoat.bumpTexture = texture; + coatNormalTexture = texture; }) ); babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem; babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem; if (properties.clearcoatNormalTexture.scale != undefined) { - babylonMaterial.clearCoat.bumpTexture!.level = properties.clearcoatNormalTexture.scale; + coatNormalTextureScale = properties.clearcoatNormalTexture.scale; } } // eslint-disable-next-line github/no-then - return Promise.all(promises).then(() => {}); + return Promise.all(promises).then(() => { + if (useOpenPBR) { + // eslint-disable-next-line github/no-then + return; + } + const material = babylonMaterial as PBRMaterial; + material.clearCoat.isEnabled = true; + material.clearCoat.useRoughnessFromMainTexture = false; + material.clearCoat.remapF0OnInterfaceChange = false; + material.clearCoat.intensity = coatWeight; + material.clearCoat.texture = coatWeightTexture; + material.clearCoat.roughness = coatRoughness; + material.clearCoat.textureRoughness = coatRoughnessTexture; + + material.clearCoat.bumpTexture = coatNormalTexture; + if (coatNormalTexture) { + material.clearCoat.bumpTexture!.level = coatNormalTextureScale; + } + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.ts index 5507ebfb1ab..5b511ac53cf 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.ts @@ -1,6 +1,7 @@ /* eslint-disable github/no-then */ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -23,6 +24,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1825) * !!! Experimental Extension Subject to Changes !!! @@ -66,10 +69,17 @@ export class KHR_materials_diffuse_transmission implements IGLTFLoaderExtension * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } promises.push(this._loadTranslucentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); return await Promise.all(promises).then(() => {}); }); @@ -77,62 +87,71 @@ export class KHR_materials_diffuse_transmission implements IGLTFLoaderExtension // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/promise-function-async private _loadTranslucentPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsDiffuseTransmission): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const pbrMaterial = babylonMaterial; - - // Enables "translucency" texture which represents diffusely-transmitted light. - pbrMaterial.subSurface.isTranslucencyEnabled = true; - - // Since this extension models thin-surface transmission only, we must make the - // internal IOR == 1.0 and set the thickness to 0. - pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0; - pbrMaterial.subSurface.minimumThickness = 0.0; - pbrMaterial.subSurface.maximumThickness = 0.0; - - // Tint color will be used for transmission. - pbrMaterial.subSurface.useAlbedoToTintTranslucency = false; + let translucencyWeight = 0.0; + let translucencyWeightTexture: Nullable; + let translucencyColor = Color3.White(); + let translucencyColorTexture: Nullable; if (extension.diffuseTransmissionFactor !== undefined) { - pbrMaterial.subSurface.translucencyIntensity = extension.diffuseTransmissionFactor; - } else { - pbrMaterial.subSurface.translucencyIntensity = 0.0; - pbrMaterial.subSurface.isTranslucencyEnabled = false; - return Promise.resolve(); + translucencyWeight = extension.diffuseTransmissionFactor; } const promises = new Array>(); - pbrMaterial.subSurface.useGltfStyleTextures = true; - if (extension.diffuseTransmissionTexture) { (extension.diffuseTransmissionTexture as ITextureInfo).nonColorData = true; promises.push( this._loader.loadTextureInfoAsync(`${context}/diffuseTransmissionTexture`, extension.diffuseTransmissionTexture).then((texture: BaseTexture) => { texture.name = `${babylonMaterial.name} (Diffuse Transmission)`; - pbrMaterial.subSurface.translucencyIntensityTexture = texture; + translucencyWeightTexture = texture; }) ); } if (extension.diffuseTransmissionColorFactor !== undefined) { - pbrMaterial.subSurface.translucencyColor = Color3.FromArray(extension.diffuseTransmissionColorFactor); - } else { - pbrMaterial.subSurface.translucencyColor = Color3.White(); + translucencyColor = Color3.FromArray(extension.diffuseTransmissionColorFactor); } if (extension.diffuseTransmissionColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/diffuseTransmissionColorTexture`, extension.diffuseTransmissionColorTexture).then((texture: BaseTexture) => { texture.name = `${babylonMaterial.name} (Diffuse Transmission Color)`; - pbrMaterial.subSurface.translucencyColorTexture = texture; + translucencyColorTexture = texture; }) ); } - return Promise.all(promises).then(() => {}); + return Promise.all(promises).then(() => { + const pbrMaterial = babylonMaterial as PBRMaterial; + + // Enables "translucency" texture which represents diffusely-transmitted light. + pbrMaterial.subSurface.isTranslucencyEnabled = true; + + // Since this extension models thin-surface transmission only, we must make the + // internal IOR == 1.0 and set the thickness to 0. + pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0; + pbrMaterial.subSurface.minimumThickness = 0.0; + pbrMaterial.subSurface.maximumThickness = 0.0; + + // Tint color will be used for transmission. + pbrMaterial.subSurface.useAlbedoToTintTranslucency = false; + + pbrMaterial.subSurface.translucencyIntensity = translucencyWeight; + if (translucencyWeight === 0.0) { + pbrMaterial.subSurface.isTranslucencyEnabled = false; + return; + } + + pbrMaterial.subSurface.useGltfStyleTextures = true; + pbrMaterial.subSurface.translucencyIntensityTexture = translucencyWeightTexture; + + pbrMaterial.subSurface.translucencyColor = translucencyColor; + pbrMaterial.subSurface.translucencyColorTexture = translucencyColorTexture; + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_dispersion.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_dispersion.ts index 1a99485b358..1783343dba8 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_dispersion.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_dispersion.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -21,6 +22,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/87bd64a7f5e23c84b6aef2e6082069583ed0ddb4/extensions/2.0/Khronos/KHR_materials_dispersion/README.md) * @experimental @@ -61,29 +64,44 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadDispersionPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsDispersion): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadDispersionPropertiesAsync( + context: string, + material: IMaterial, + babylonMaterial: Material, + extension: IKHRMaterialsDispersion, + useOpenPBR: boolean = false + ): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - // If transparency isn't enabled already, this extension shouldn't do anything. - // i.e. it requires either the KHR_materials_transmission or KHR_materials_diffuse_transmission extensions. - if (!babylonMaterial.subSurface.isRefractionEnabled || !extension.dispersion) { - return Promise.resolve(); + if (!useOpenPBR) { + // If transparency isn't enabled already, this extension shouldn't do anything. + // i.e. it requires either the KHR_materials_transmission or KHR_materials_diffuse_transmission extensions. + if (!(babylonMaterial as PBRMaterial).subSurface.isRefractionEnabled || !extension.dispersion) { + return Promise.resolve(); + } + (babylonMaterial as PBRMaterial).subSurface.isDispersionEnabled = true; + (babylonMaterial as PBRMaterial).subSurface.dispersion = extension.dispersion; } - babylonMaterial.subSurface.isDispersionEnabled = true; - babylonMaterial.subSurface.dispersion = extension.dispersion; return Promise.resolve(); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_emissive_strength.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_emissive_strength.ts index b2c0e1a0e41..690a54a4c7e 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_emissive_strength.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_emissive_strength.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -21,6 +22,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md) */ @@ -60,17 +63,23 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { - // eslint-disable-next-line github/no-then - return await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial).then(() => { - this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); - }); + await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); + return await Promise.resolve(); }); } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_ior.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_ior.ts index ad70f99ba58..08a06b1ab9d 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_ior.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_ior.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -21,6 +22,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_ior/README.md) */ @@ -65,26 +68,38 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadIorPropertiesAsync(context: string, properties: IKHRMaterialsIor, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadIorPropertiesAsync(context: string, properties: IKHRMaterialsIor, babylonMaterial: Material, useOpenPBR: boolean = false): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } + let indexOfRefraction = 1.5; if (properties.ior !== undefined) { - babylonMaterial.indexOfRefraction = properties.ior; + indexOfRefraction = properties.ior; } else { - babylonMaterial.indexOfRefraction = KHR_materials_ior._DEFAULT_IOR; + indexOfRefraction = KHR_materials_ior._DEFAULT_IOR; + } + + if (!useOpenPBR) { + (babylonMaterial as PBRMaterial).indexOfRefraction = indexOfRefraction; } return Promise.resolve(); diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_iridescence.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_iridescence.ts index 11168af02da..5bd277b1e6f 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_iridescence.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_iridescence.ts @@ -1,6 +1,8 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; +import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -21,6 +23,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_iridescence/README.md) */ @@ -60,36 +64,48 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsIridescence, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsIridescence, babylonMaterial: Material, useOpenPBR: boolean = false): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const promises = new Array>(); + let iridescenceWeight = 0.0; + let iridescenceWeightTexture: Nullable = null; + let iridescenceIor = 1.3; + let iridescenceThicknessMinimum = 100; + let iridescenceThicknessMaximum = 400; + let iridescenceThicknessTexture: Nullable = null; - babylonMaterial.iridescence.isEnabled = true; + const promises = new Array>(); - babylonMaterial.iridescence.intensity = properties.iridescenceFactor ?? 0; - babylonMaterial.iridescence.indexOfRefraction = properties.iridescenceIor ?? (properties as any).iridescenceIOR ?? 1.3; - babylonMaterial.iridescence.minimumThickness = properties.iridescenceThicknessMinimum ?? 100; - babylonMaterial.iridescence.maximumThickness = properties.iridescenceThicknessMaximum ?? 400; + iridescenceWeight = properties.iridescenceFactor ?? 0; + iridescenceIor = properties.iridescenceIor ?? (properties as any).iridescenceIOR ?? 1.3; + iridescenceThicknessMinimum = properties.iridescenceThicknessMinimum ?? 100; + iridescenceThicknessMaximum = properties.iridescenceThicknessMaximum ?? 400; if (properties.iridescenceTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/iridescenceTexture`, properties.iridescenceTexture, (texture) => { texture.name = `${babylonMaterial.name} (Iridescence)`; - babylonMaterial.iridescence.texture = texture; + iridescenceWeightTexture = texture; }) ); } @@ -98,13 +114,23 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/iridescenceThicknessTexture`, properties.iridescenceThicknessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Iridescence Thickness)`; - babylonMaterial.iridescence.thicknessTexture = texture; + iridescenceThicknessTexture = texture; }) ); } // eslint-disable-next-line github/no-then - return Promise.all(promises).then(() => {}); + return Promise.all(promises).then(() => { + const pbrMaterial = babylonMaterial as PBRMaterial; + pbrMaterial.iridescence.isEnabled = true; + + pbrMaterial.iridescence.intensity = iridescenceWeight; + pbrMaterial.iridescence.indexOfRefraction = iridescenceIor; + pbrMaterial.iridescence.minimumThickness = iridescenceThicknessMinimum; + pbrMaterial.iridescence.maximumThickness = iridescenceThicknessMaximum; + pbrMaterial.iridescence.texture = iridescenceWeightTexture; + pbrMaterial.iridescence.thicknessTexture = iridescenceThicknessTexture; + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts index 4816792a5e3..cea6ceb4f3c 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts @@ -1,6 +1,8 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; +import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -22,6 +24,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_sheen/README.md) * [Playground Sample](https://www.babylonjs-playground.com/frame.html#BNIZX6#4) @@ -62,46 +66,51 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadSheenPropertiesAsync(context: string, properties: IKHRMaterialsSheen, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadSheenPropertiesAsync(context: string, properties: IKHRMaterialsSheen, babylonMaterial: Material, useOpenPBR: boolean): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const promises = new Array>(); + let sheenColor = Color3.Black(); + let sheenColorTexture: Nullable = null; + let sheenRoughness = 0.0; + let sheenRoughnessTexture: Nullable = null; - babylonMaterial.sheen.isEnabled = true; - babylonMaterial.sheen.intensity = 1; + const promises = new Array>(); if (properties.sheenColorFactor != undefined) { - babylonMaterial.sheen.color = Color3.FromArray(properties.sheenColorFactor); - } else { - babylonMaterial.sheen.color = Color3.Black(); + sheenColor = Color3.FromArray(properties.sheenColorFactor); } if (properties.sheenColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/sheenColorTexture`, properties.sheenColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Sheen Color)`; - babylonMaterial.sheen.texture = texture; + sheenColorTexture = texture; }) ); } if (properties.sheenRoughnessFactor !== undefined) { - babylonMaterial.sheen.roughness = properties.sheenRoughnessFactor; - } else { - babylonMaterial.sheen.roughness = 0; + sheenRoughness = properties.sheenRoughnessFactor; } if (properties.sheenRoughnessTexture) { @@ -109,16 +118,26 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/sheenRoughnessTexture`, properties.sheenRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Sheen Roughness)`; - babylonMaterial.sheen.textureRoughness = texture; + sheenRoughnessTexture = texture; }) ); } - babylonMaterial.sheen.albedoScaling = true; - babylonMaterial.sheen.useRoughnessFromMainTexture = false; - // eslint-disable-next-line github/no-then - return Promise.all(promises).then(() => {}); + return Promise.all(promises).then(() => { + if (useOpenPBR) { + return; + } + const pbrMaterial = babylonMaterial as PBRMaterial; + pbrMaterial.sheen.isEnabled = true; + pbrMaterial.sheen.intensity = 1; + pbrMaterial.sheen.color = sheenColor; + pbrMaterial.sheen.texture = sheenColorTexture; + pbrMaterial.sheen.roughness = sheenRoughness; + pbrMaterial.sheen.textureRoughness = sheenRoughnessTexture; + pbrMaterial.sheen.albedoScaling = true; + pbrMaterial.sheen.useRoughnessFromMainTexture = false; + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts index 38cbf494cd9..61d705cb697 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -23,6 +24,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular/README.md) */ @@ -62,18 +65,25 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // Handle the EXT_materials_specular_edge_color sub-extension // https://github.com/KhronosGroup/glTF/blob/2a1111b88f052cbd3e2d82abb9faee56e7494904/extensions/2.0/Vendor/EXT_materials_specular_edge_color/README.md - if (extension.extensions && extension.extensions.EXT_materials_specular_edge_color && babylonMaterial instanceof PBRMaterial) { + if (!useOpenPBR && extension.extensions && extension.extensions.EXT_materials_specular_edge_color) { const specularEdgeColorExtension = extension.extensions.EXT_materials_specular_edge_color as IEXTMaterialsSpecularEdgeColor; if (specularEdgeColorExtension.specularEdgeColorEnabled) { - babylonMaterial.brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR; - babylonMaterial.brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR; + (babylonMaterial as PBRMaterial).brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR; + (babylonMaterial as PBRMaterial).brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR; } } // eslint-disable-next-line github/no-then @@ -82,39 +92,69 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material, useOpenPBR: boolean): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - if (properties.specularFactor !== undefined) { - babylonMaterial.metallicF0Factor = properties.specularFactor; - } + if (useOpenPBR) { + if (properties.specularFactor !== undefined) { + (babylonMaterial as OpenPBRMaterial).specularWeight = properties.specularFactor; + } - if (properties.specularColorFactor !== undefined) { - babylonMaterial.metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); - } + if (properties.specularColorFactor !== undefined) { + (babylonMaterial as OpenPBRMaterial).specularColor = Color3.FromArray(properties.specularColorFactor); + } - if (properties.specularTexture) { - (properties.specularTexture as ITextureInfo).nonColorData = true; - promises.push( - this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => { - texture.name = `${babylonMaterial.name} (Specular)`; - babylonMaterial.metallicReflectanceTexture = texture; - babylonMaterial.useOnlyMetallicFromMetallicReflectanceTexture = true; - }) - ); - } + if (properties.specularTexture) { + (properties.specularTexture as ITextureInfo).nonColorData = true; + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular)`; + (babylonMaterial as OpenPBRMaterial).specularWeightTexture = texture; + (babylonMaterial as OpenPBRMaterial).useSpecularWeightFromTextureAlpha = true; + }) + ); + } - if (properties.specularColorTexture) { - promises.push( - this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { - texture.name = `${babylonMaterial.name} (Specular Color)`; - babylonMaterial.reflectanceTexture = texture; - }) - ); + if (properties.specularColorTexture) { + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular Color)`; + (babylonMaterial as OpenPBRMaterial).specularColorTexture = texture; + }) + ); + } + } else { + if (properties.specularFactor !== undefined) { + (babylonMaterial as PBRMaterial).metallicF0Factor = properties.specularFactor; + } + + if (properties.specularColorFactor !== undefined) { + (babylonMaterial as PBRMaterial).metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); + } + + if (properties.specularTexture) { + (properties.specularTexture as ITextureInfo).nonColorData = true; + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular)`; + (babylonMaterial as PBRMaterial).metallicReflectanceTexture = texture; + (babylonMaterial as PBRMaterial).useOnlyMetallicFromMetallicReflectanceTexture = true; + }) + ); + } + + if (properties.specularColorTexture) { + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular Color)`; + (babylonMaterial as PBRMaterial).reflectionTexture = texture; + }) + ); + } } // eslint-disable-next-line github/no-then diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts index 5f91a41d555..c0022868174 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts @@ -1,5 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -62,6 +63,8 @@ interface ITransmissionHelperOptions { clearColor?: Color4; } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * A class to handle setting up the rendering of opaque objects to be shown through transmissive objects. */ @@ -166,7 +169,7 @@ class TransmissionHelper { if (!material) { return false; } - if (material instanceof PBRMaterial && material.subSurface.isRefractionEnabled) { + if (material instanceof PBRMaterialClass && (material as any).subSurface.isRefractionEnabled) { return true; } return false; @@ -220,8 +223,8 @@ class TransmissionHelper { // If the material is transparent, make sure that it's added to the transparent list and removed from the opaque list const useTransmission = this._shouldRenderAsTransmission(mesh.material); if (useTransmission) { - if (mesh.material instanceof PBRMaterial) { - mesh.material.subSurface.refractionTexture = this._opaqueRenderTarget; + if (mesh.material instanceof PBRMaterialClass) { + (mesh.material as any).subSurface.refractionTexture = this._opaqueRenderTarget; } if (opaqueIdx !== -1) { this._opaqueMeshesCache.splice(opaqueIdx, 1); @@ -366,60 +369,87 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/promise-function-async - private _loadTransparentPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsTransmission): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadTransparentPropertiesAsync( + context: string, + material: IMaterial, + babylonMaterial: Material, + extension: IKHRMaterialsTransmission, + useOpenPBR: boolean + ): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const pbrMaterial = babylonMaterial; - - // Enables "refraction" texture which represents transmitted light. - pbrMaterial.subSurface.isRefractionEnabled = true; - - // Since this extension models thin-surface transmission only, we must make IOR = 1.0 - pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0; - // Albedo colour will tint transmission. - pbrMaterial.subSurface.useAlbedoToTintRefraction = true; + let transmissionWeight = 0.0; + let transmissionWeightTexture: Nullable = null; + const promises = new Array>(); if (extension.transmissionFactor !== undefined) { - pbrMaterial.subSurface.refractionIntensity = extension.transmissionFactor; - const scene = pbrMaterial.getScene() as unknown as ITransmissionHelperHolder; - if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper) { - new TransmissionHelper({}, pbrMaterial.getScene()); - } else if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper?._isRenderTargetValid()) { - // If the render target is not valid, recreate it. - scene._transmissionHelper?._setupRenderTargets(); - } + transmissionWeight = extension.transmissionFactor; } else { - pbrMaterial.subSurface.refractionIntensity = 0.0; - pbrMaterial.subSurface.isRefractionEnabled = false; return Promise.resolve(); } - - pbrMaterial.subSurface.minimumThickness = 0.0; - pbrMaterial.subSurface.maximumThickness = 0.0; if (extension.transmissionTexture) { (extension.transmissionTexture as ITextureInfo).nonColorData = true; // eslint-disable-next-line github/no-then - return this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, undefined).then((texture: BaseTexture) => { - texture.name = `${babylonMaterial.name} (Transmission)`; - pbrMaterial.subSurface.refractionIntensityTexture = texture; - pbrMaterial.subSurface.useGltfStyleTextures = true; - }); - } else { - return Promise.resolve(); + promises.push( + this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, (texture: BaseTexture) => { + texture.name = `${babylonMaterial.name} (Transmission)`; + transmissionWeightTexture = texture; + }) + ); } + + // eslint-disable-next-line github/no-then + return Promise.all(promises).then(() => { + if (useOpenPBR) { + return; + } + const pbrMaterial = babylonMaterial as PBRMaterial; + + // Enables "refraction" texture which represents transmitted light. + pbrMaterial.subSurface.isRefractionEnabled = transmissionWeight !== 0; + + // Since this extension models thin-surface transmission only, we must make IOR = 1.0 + pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0; + + // Albedo colour will tint transmission. + pbrMaterial.subSurface.useAlbedoToTintRefraction = true; + + pbrMaterial.subSurface.refractionIntensity = transmissionWeight; + + if (transmissionWeight) { + const scene = pbrMaterial.getScene() as unknown as ITransmissionHelperHolder; + if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper) { + new TransmissionHelper({}, pbrMaterial.getScene()); + } else if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper?._isRenderTargetValid()) { + // If the render target is not valid, recreate it. + scene._transmissionHelper?._setupRenderTargets(); + } + } + pbrMaterial.subSurface.minimumThickness = 0.0; + pbrMaterial.subSurface.maximumThickness = 0.0; + pbrMaterial.subSurface.refractionIntensityTexture = transmissionWeightTexture; + pbrMaterial.subSurface.useGltfStyleTextures = true; + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts index 1a9609ac33c..056511dbb80 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts @@ -1,6 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -21,6 +22,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_unlit/README.md) */ @@ -60,40 +63,58 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async () => { - return await this._loadUnlitPropertiesAsync(context, material, babylonMaterial); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + return await this._loadUnlitPropertiesAsync(context, material, babylonMaterial, useOpenPBR); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadUnlitPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadUnlitPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); babylonMaterial.unlit = true; - + let baseColor: Color3 = Color3.White(); + let alpha: number = 1; const properties = material.pbrMetallicRoughness; if (properties) { if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.alpha = properties.baseColorFactor[3]; - } else { - babylonMaterial.albedoColor = Color3.White(); + baseColor = Color3.FromArray(properties.baseColorFactor); + alpha = properties.baseColorFactor[3]; } if (properties.baseColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Base Color)`; - babylonMaterial.albedoTexture = texture; + if (useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; + } else { + (babylonMaterial as PBRMaterial).albedoTexture = texture; + } }) ); } } + if (useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColor = baseColor; + (babylonMaterial as OpenPBRMaterial).geometryOpacity = alpha; + } else { + (babylonMaterial as PBRMaterial).albedoColor = baseColor; + (babylonMaterial as PBRMaterial).alpha = alpha; + } + if (material.doubleSided) { babylonMaterial.backFaceCulling = false; babylonMaterial.twoSidedLighting = true; diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts index 349cbd67c10..f3e39c352d4 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts @@ -1,7 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; +import { Color3 } from "core/Maths/math.color"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -22,6 +24,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** * [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md) * @since 5.0.0 @@ -69,50 +73,85 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension)); + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadVolumePropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsVolume): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + private _loadVolumePropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsVolume, useOpenPBR: boolean): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } + if (useOpenPBR) { + return Promise.resolve(); + } // If transparency isn't enabled already, this extension shouldn't do anything. // i.e. it requires either the KHR_materials_transmission or KHR_materials_diffuse_transmission extensions. - if ((!babylonMaterial.subSurface.isRefractionEnabled && !babylonMaterial.subSurface.isTranslucencyEnabled) || !extension.thicknessFactor) { + if ( + (!(babylonMaterial as PBRMaterial).subSurface.isRefractionEnabled && !(babylonMaterial as PBRMaterial).subSurface.isTranslucencyEnabled) || + !extension.thicknessFactor + ) { return Promise.resolve(); } - // IOR in this extension only affects interior. - babylonMaterial.subSurface.volumeIndexOfRefraction = babylonMaterial.indexOfRefraction; - const attenuationDistance = extension.attenuationDistance !== undefined ? extension.attenuationDistance : Number.MAX_VALUE; - babylonMaterial.subSurface.tintColorAtDistance = attenuationDistance; + let attenuationDistance = Number.MAX_VALUE; + const attenuationColor: Color3 = Color3.White(); + let thicknessTexture: Nullable = null; + let thicknessFactor = 0.0; + + const promises = new Array>(); + + attenuationDistance = extension.attenuationDistance !== undefined ? extension.attenuationDistance : Number.MAX_VALUE; if (extension.attenuationColor !== undefined && extension.attenuationColor.length == 3) { - babylonMaterial.subSurface.tintColor.copyFromFloats(extension.attenuationColor[0], extension.attenuationColor[1], extension.attenuationColor[2]); + attenuationColor.copyFromFloats(extension.attenuationColor[0], extension.attenuationColor[1], extension.attenuationColor[2]); } - babylonMaterial.subSurface.minimumThickness = 0.0; - babylonMaterial.subSurface.maximumThickness = extension.thicknessFactor; - babylonMaterial.subSurface.useThicknessAsDepth = true; + thicknessFactor = extension.thicknessFactor; if (extension.thicknessTexture) { (extension.thicknessTexture as ITextureInfo).nonColorData = true; // eslint-disable-next-line github/no-then - return this._loader.loadTextureInfoAsync(`${context}/thicknessTexture`, extension.thicknessTexture).then((texture: BaseTexture) => { - texture.name = `${babylonMaterial.name} (Thickness)`; - babylonMaterial.subSurface.thicknessTexture = texture; - babylonMaterial.subSurface.useGltfStyleTextures = true; - }); - } else { - return Promise.resolve(); + promises.push( + this._loader.loadTextureInfoAsync(`${context}/thicknessTexture`, extension.thicknessTexture, (texture: BaseTexture) => { + texture.name = `${babylonMaterial.name} (Thickness)`; + thicknessTexture = texture; + }) + ); } + + // eslint-disable-next-line github/no-then + return Promise.all(promises).then(() => { + if (useOpenPBR) { + return; + } + + const pbrMaterial = babylonMaterial as PBRMaterial; + // IOR in this extension only affects interior. + pbrMaterial.subSurface.volumeIndexOfRefraction = pbrMaterial.indexOfRefraction; + pbrMaterial.subSurface.tintColorAtDistance = attenuationDistance; + pbrMaterial.subSurface.tintColor = attenuationColor; + + pbrMaterial.subSurface.minimumThickness = 0.0; + pbrMaterial.subSurface.maximumThickness = thicknessFactor; + pbrMaterial.subSurface.useThicknessAsDepth = true; + if (thicknessTexture) { + pbrMaterial.subSurface.thicknessTexture = thicknessTexture; + pbrMaterial.subSurface.useGltfStyleTextures = true; + } + }); } } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts index 84055b9c49b..ecb866e40c5 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts @@ -1,6 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -20,6 +21,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** @internal */ // eslint-disable-next-line @typescript-eslint/naming-convention export class MSFT_minecraftMesh implements IGLTFLoaderExtension { @@ -44,10 +47,17 @@ export class MSFT_minecraftMesh implements IGLTFLoaderExtension { /** @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } if (extra) { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${extraContext}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts index ab98d23ed09..815545e6e4b 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts @@ -1,6 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -20,6 +21,8 @@ declare module "../../glTFFileLoader" { } } +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + /** @internal */ // eslint-disable-next-line @typescript-eslint/naming-convention export class MSFT_sRGBFactors implements IGLTFLoaderExtension { @@ -44,22 +47,37 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { /** @internal*/ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { + if (useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } if (extra) { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${extraContext}: Material type not supported`); } const promise = this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial); const useExactSrgbConversions = babylonMaterial.getScene().getEngine().useExactSrgbConversions; - if (!babylonMaterial.albedoTexture) { - babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); - } - - if (!babylonMaterial.reflectivityTexture) { - babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor, useExactSrgbConversions); + if (useOpenPBR) { + if (!(babylonMaterial as OpenPBRMaterial).baseColorTexture) { + (babylonMaterial as OpenPBRMaterial).baseColor.toLinearSpaceToRef((babylonMaterial as OpenPBRMaterial).baseColor, useExactSrgbConversions); + } + if (!(babylonMaterial as OpenPBRMaterial).specularColorTexture) { + (babylonMaterial as OpenPBRMaterial).specularColor.toLinearSpaceToRef((babylonMaterial as OpenPBRMaterial).specularColor, useExactSrgbConversions); + } + } else { + if (!(babylonMaterial as PBRMaterial).albedoTexture) { + (babylonMaterial as PBRMaterial).albedoColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).albedoColor, useExactSrgbConversions); + } + if (!(babylonMaterial as PBRMaterial).reflectivityTexture) { + (babylonMaterial as PBRMaterial).reflectivityColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).reflectivityColor, useExactSrgbConversions); + } } return await promise; diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index b199e919678..53bb821a4d5 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -16,7 +16,8 @@ import type { AnimationGroup } from "core/Animations/animationGroup"; import { Bone } from "core/Bones/bone"; import { Skeleton } from "core/Bones/skeleton"; import { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { ITextureCreationOptions } from "core/Materials/Textures/texture"; import { Texture } from "core/Materials/Textures/texture"; @@ -86,6 +87,8 @@ import { GetTypedArrayConstructor } from "core/Buffers/bufferUtils"; export { GLTFFileLoader }; +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + interface ILoaderProperty extends IProperty { _activeLoaderExtensionFunctions: { [id: string]: boolean; @@ -399,6 +402,14 @@ export class GLTFLoader implements IGLTFLoader { await this._loadExtensionsAsync(); + if (this.parent.useOpenPBR) { + const mod = await import("core/Materials/PBR/openPbrMaterial"); + PBRMaterialClass = mod.OpenPBRMaterial; + } else { + const mod = await import("core/Materials/PBR/pbrMaterial"); + PBRMaterialClass = mod.PBRMaterial; + } + const loadingToReadyCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.READY]}`; const loadingToCompleteCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.COMPLETE]}`; @@ -2127,28 +2138,45 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); if (properties) { - if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.alpha = properties.baseColorFactor[3]; + if (this.parent.useOpenPBR) { + const mat = babylonMaterial as OpenPBRMaterial; + if (properties.baseColorFactor) { + mat.baseColor = Color3.FromArray(properties.baseColorFactor); + mat.geometryOpacity = properties.baseColorFactor[3]; + } else { + mat.baseColor = Color3.White(); + } + mat.baseMetalness = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + mat.specularRoughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; } else { - babylonMaterial.albedoColor = Color3.White(); + const mat = babylonMaterial as PBRMaterial; + if (properties.baseColorFactor) { + mat.albedoColor = Color3.FromArray(properties.baseColorFactor); + mat.alpha = properties.baseColorFactor[3]; + } else { + mat.albedoColor = Color3.White(); + } + mat.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + mat.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + babylonMaterial = mat; } - babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; - babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; - if (properties.baseColorTexture) { promises.push( this.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Base Color)`; - babylonMaterial.albedoTexture = texture; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; + } else { + (babylonMaterial as PBRMaterial).albedoTexture = texture; + } }) ); } @@ -2158,13 +2186,19 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Metallic Roughness)`; - babylonMaterial.metallicTexture = texture; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseMetalRoughTexture = texture; + } else { + (babylonMaterial as PBRMaterial).metallicTexture = texture; + } }) ); - babylonMaterial.useMetallnessFromMetallicTextureBlue = true; - babylonMaterial.useRoughnessFromMetallicTextureGreen = true; - babylonMaterial.useRoughnessFromMetallicTextureAlpha = false; + if (!this.parent.useOpenPBR) { + (babylonMaterial as PBRMaterial).useMetallnessFromMetallicTextureBlue = true; + (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureGreen = true; + (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureAlpha = false; + } } } @@ -2227,17 +2261,17 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; - const babylonMaterial = new PBRMaterial(name, this._babylonScene); + const babylonMaterial = new PBRMaterialClass(name, this._babylonScene); babylonMaterial._parentContainer = this._assetContainer; this._babylonScene._blockEntityCollection = false; // Moved to mesh so user can change materials on gltf meshes: babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation; babylonMaterial.fillMode = babylonDrawMode; babylonMaterial.enableSpecularAntiAliasing = true; - babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage; - babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage; - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; - babylonMaterial.metallic = 1; - babylonMaterial.roughness = 1; + if (!this.parent.useOpenPBR) { + (babylonMaterial as PBRMaterial).useRadianceOverAlpha = !this._parent.transparencyAsCoverage; + (babylonMaterial as PBRMaterial).useSpecularOverAlpha = !this._parent.transparencyAsCoverage; + } + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; return babylonMaterial; } @@ -2295,13 +2329,17 @@ export class GLTFLoader implements IGLTFLoader { * @returns A promise that resolves when the load is complete */ public loadMaterialBasePropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).emissionColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + } else { + (babylonMaterial as PBRMaterial).emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + } if (material.doubleSided) { babylonMaterial.backFaceCulling = false; babylonMaterial.twoSidedLighting = true; @@ -2325,18 +2363,21 @@ export class GLTFLoader implements IGLTFLoader { babylonMaterial.forceIrradianceInFragment = true; } + let aoTexture: BaseTexture; + let aoStrength: number = 1.0; + let emissionTexture: BaseTexture; + if (material.occlusionTexture) { material.occlusionTexture.nonColorData = true; promises.push( this.loadTextureInfoAsync(`${context}/occlusionTexture`, material.occlusionTexture, (texture) => { texture.name = `${babylonMaterial.name} (Occlusion)`; - babylonMaterial.ambientTexture = texture; + aoTexture = texture; }) ); - babylonMaterial.useAmbientInGrayScale = true; if (material.occlusionTexture.strength != undefined) { - babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength; + aoStrength = material.occlusionTexture.strength; } } @@ -2344,12 +2385,25 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/emissiveTexture`, material.emissiveTexture, (texture) => { texture.name = `${babylonMaterial.name} (Emissive)`; - babylonMaterial.emissiveTexture = texture; + emissionTexture = texture; }) ); } - return Promise.all(promises).then(() => {}); + return Promise.all(promises).then(() => { + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).ambientOcclusionTexture = aoTexture; + (babylonMaterial as OpenPBRMaterial).emissionTexture = emissionTexture; + if (aoTexture) { + (babylonMaterial as OpenPBRMaterial).ambientOcclusionTexture.level = aoStrength; + } + } else { + (babylonMaterial as PBRMaterial).ambientTexture = aoTexture; + (babylonMaterial as PBRMaterial).emissiveTexture = emissionTexture; + (babylonMaterial as PBRMaterial).useAmbientInGrayScale = true; + (babylonMaterial as PBRMaterial).ambientTextureStrength = aoStrength; + } + }); } /** @@ -2360,29 +2414,31 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } + const baseColorTexture = this.parent.useOpenPBR ? (babylonMaterial as OpenPBRMaterial).baseColorTexture : (babylonMaterial as PBRMaterial).albedoTexture; + const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE; switch (alphaMode) { case MaterialAlphaMode.OPAQUE: { - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; babylonMaterial.alpha = 1.0; // Force alpha to 1.0 for opaque mode. break; } case MaterialAlphaMode.MASK: { - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHATEST; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHATEST; babylonMaterial.alphaCutOff = material.alphaCutoff == undefined ? 0.5 : material.alphaCutoff; - if (babylonMaterial.albedoTexture) { - babylonMaterial.albedoTexture.hasAlpha = true; + if (baseColorTexture) { + baseColorTexture.hasAlpha = true; } break; } case MaterialAlphaMode.BLEND: { - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND; - if (babylonMaterial.albedoTexture) { - babylonMaterial.albedoTexture.hasAlpha = true; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHABLEND; + if (baseColorTexture) { + baseColorTexture.hasAlpha = true; babylonMaterial.useAlphaFromAlbedoTexture = true; } break; @@ -2901,7 +2957,7 @@ export class GLTFLoader implements IGLTFLoader { return this._applyExtensions( material, "loadMaterialProperties", - (extension) => extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial) + (extension) => extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial, this.parent.useOpenPBR) ); } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts index 72ae55dce23..15930ba12e6 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts @@ -127,9 +127,10 @@ export interface IGLTFLoaderExtension extends IGLTFBaseLoaderExtension, IDisposa * @param context The context when loading the asset * @param material The glTF material property * @param babylonMaterial The Babylon material + * @param useOpenPBR Load materials as OpenPBR materials instead of glTF PBR materials. * @returns A promise that resolves when the load is complete or null if not handled */ - loadMaterialPropertiesAsync?(context: string, material: IMaterial, babylonMaterial: Material): Nullable>; + loadMaterialPropertiesAsync?(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean): Nullable>; /** * Define this method to modify the default behavior when loading texture infos. diff --git a/packages/dev/loaders/src/glTF/glTFFileLoader.ts b/packages/dev/loaders/src/glTF/glTFFileLoader.ts index 4da0f4a44c3..2e0e712506b 100644 --- a/packages/dev/loaders/src/glTF/glTFFileLoader.ts +++ b/packages/dev/loaders/src/glTF/glTFFileLoader.ts @@ -206,6 +206,7 @@ abstract class GLTFLoaderOptions { this.compileShadowGenerators = options.compileShadowGenerators ?? this.compileShadowGenerators; this.transparencyAsCoverage = options.transparencyAsCoverage ?? this.transparencyAsCoverage; this.useRangeRequests = options.useRangeRequests ?? this.useRangeRequests; + this.useOpenPBR = options.useOpenPBR ?? this.useOpenPBR; this.createInstances = options.createInstances ?? this.createInstances; this.alwaysComputeBoundingBox = options.alwaysComputeBoundingBox ?? this.alwaysComputeBoundingBox; this.loadAllMaterials = options.loadAllMaterials ?? this.loadAllMaterials; @@ -294,6 +295,11 @@ abstract class GLTFLoaderOptions { */ public useRangeRequests = false; + /** + * Load the glTF files using the PBR2 material. + */ + public useOpenPBR = false; + /** * Defines if the loader should create instances when multiple glTF nodes point to the same glTF mesh. Defaults to true. */ diff --git a/packages/tools/sandbox/src/tools/environmentTools.ts b/packages/tools/sandbox/src/tools/environmentTools.ts index e1bc486f171..ef2d57e0407 100644 --- a/packages/tools/sandbox/src/tools/environmentTools.ts +++ b/packages/tools/sandbox/src/tools/environmentTools.ts @@ -7,6 +7,7 @@ import type { StandardMaterial } from "core/Materials/standardMaterial"; import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import { Texture } from "core/Materials/Textures/texture"; import { EngineStore } from "core/Engines/engineStore"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; export class EnvironmentTools { public static SkyboxPath = ""; @@ -56,7 +57,7 @@ export class EnvironmentTools { currentScene.environmentTexture = this.LoadSkyboxPathTexture(currentScene); for (let i = 0; i < currentScene.materials.length; i++) { - const material = currentScene.materials[i] as StandardMaterial | PBRMaterial; + const material = currentScene.materials[i] as StandardMaterial | PBRMaterial | OpenPBRMaterial; if (material.name === "skyBox") { const reflectionTexture = material.reflectionTexture; if (reflectionTexture && reflectionTexture.coordinatesMode === Texture.SKYBOX_MODE) {