From 2c7ad5ec38bc26f7294bed7576be772f13e4915c Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Thu, 19 Jun 2025 13:20:41 -0700 Subject: [PATCH 01/45] Added PBR2 material and option to load using glTF --- packages/dev/core/src/Materials/PBR/index.ts | 5 + .../core/src/Materials/PBR/pbrMaterial2.ts | 2138 +++++++++++++++++ .../dev/core/src/Shaders/pbr2.fragment.fx | 692 ++++++ packages/dev/core/src/Shaders/pbr2.vertex.fx | 312 +++ .../dev/core/src/ShadersWGSL/pbr2.fragment.fx | 688 ++++++ .../dev/core/src/ShadersWGSL/pbr2.vertex.fx | 295 +++ .../EXT_materials_diffuse_roughness.ts | 3 +- .../Extensions/KHR_materials_anisotropy.ts | 3 +- .../2.0/Extensions/KHR_materials_clearcoat.ts | 3 +- .../KHR_materials_diffuse_transmission.ts | 3 +- .../Extensions/KHR_materials_dispersion.ts | 3 +- .../KHR_materials_emissive_strength.ts | 3 +- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 3 +- .../Extensions/KHR_materials_iridescence.ts | 3 +- .../KHR_materials_pbrSpecularGlossiness.ts | 3 +- .../2.0/Extensions/KHR_materials_sheen.ts | 3 +- .../2.0/Extensions/KHR_materials_specular.ts | 3 +- .../Extensions/KHR_materials_transmission.ts | 3 +- .../2.0/Extensions/KHR_materials_unlit.ts | 3 +- .../2.0/Extensions/KHR_materials_volume.ts | 3 +- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 3 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 3 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 14 +- .../dev/loaders/src/glTF/glTFFileLoader.ts | 6 + 24 files changed, 4178 insertions(+), 20 deletions(-) create mode 100644 packages/dev/core/src/Materials/PBR/pbrMaterial2.ts create mode 100644 packages/dev/core/src/Shaders/pbr2.fragment.fx create mode 100644 packages/dev/core/src/Shaders/pbr2.vertex.fx create mode 100644 packages/dev/core/src/ShadersWGSL/pbr2.fragment.fx create mode 100644 packages/dev/core/src/ShadersWGSL/pbr2.vertex.fx diff --git a/packages/dev/core/src/Materials/PBR/index.ts b/packages/dev/core/src/Materials/PBR/index.ts index f97e5346890..a04f9cd3f91 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 "./pbrMaterial2"; 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/pbr2.vertex"; +export * from "../../ShadersWGSL/pbr2.fragment"; +export * from "../../Shaders/pbr2.vertex"; +export * from "../../Shaders/pbr2.fragment"; diff --git a/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts b/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts new file mode 100644 index 00000000000..39ef0957c06 --- /dev/null +++ b/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts @@ -0,0 +1,2138 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture } from "../../Misc/decorators"; +import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; +import type { Nullable } from "../../types"; +import type { Scene } from "../../scene"; +import { Color3 } from "../../Maths/math.color"; +import { 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"; +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 "../../Materials/materialDefines"; +import type { IImageProcessingConfigurationDefines } from "../../Materials/imageProcessingConfiguration.defines"; +import { EffectFallbacks } from "../effectFallbacks"; +import { AddClipPlaneUniforms } from "../clipPlaneMaterialHelper"; +import { + // BindBonesParameters, + // BindFogParameters, + // BindLights, + // BindLogDepth, + // BindMorphTargetParameters, + // BindTextureMatrix, + HandleFallbacksForShadows, + PrepareAttributesForBakedVertexAnimation, + PrepareAttributesForBones, + PrepareAttributesForInstances, + PrepareAttributesForMorphTargets, + PrepareDefinesForAttributes, + PrepareDefinesForFrameBoundValues, + PrepareDefinesForLights, + PrepareDefinesForMergedUV, + PrepareDefinesForMisc, + PrepareDefinesForMultiview, + PrepareDefinesForOIT, + PrepareDefinesForPrePass, + PrepareUniformsAndSamplersList, +} 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 { Texture } from "../../Materials/Textures/texture"; +import type { SubMesh } from "../../Meshes/subMesh"; +import { Logger } from "core/Misc/logger"; + +const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; +/** + * Manages the defines for the PBR Material. + * @internal + */ +export class PBRMaterial2Defines extends MaterialDefines implements IImageProcessingConfigurationDefines { + 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; + public ALBEDODIRECTUV = 0; + public VERTEXCOLOR = false; + + public BASE_WEIGHT = false; + public BASE_WEIGHTDIRECTUV = 0; + public BASE_DIFFUSE_ROUGHNESS = false; + public BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; + + public BAKED_VERTEX_ANIMATION_TEXTURE = false; + + public AMBIENT = false; + public AMBIENTDIRECTUV = 0; + public AMBIENTINGRAYSCALE = false; + + public OPACITY = false; + public VERTEXALPHA = false; + public OPACITYDIRECTUV = 0; + public OPACITYRGB = false; + public ALPHATEST = false; + public DEPTHPREPASS = false; + public ALPHABLEND = false; + public ALPHAFROMALBEDO = false; + public ALPHATESTVALUE = "0.5"; + public SPECULAROVERALPHA = false; + public RADIANCEOVERALPHA = false; + public ALPHAFRESNEL = false; + public LINEARALPHAFRESNEL = false; + public PREMULTIPLYALPHA = false; + + public EMISSIVE = false; + public EMISSIVEDIRECTUV = 0; + public GAMMAEMISSIVE = false; + + public REFLECTIVITY = false; + public REFLECTIVITY_GAMMA = false; + public REFLECTIVITYDIRECTUV = 0; + public SPECULARTERM = false; + + public MICROSURFACEFROMREFLECTIVITYMAP = false; + public MICROSURFACEAUTOMATIC = false; + public LODBASEDMICROSFURACE = false; + public MICROSURFACEMAP = false; + public MICROSURFACEMAPDIRECTUV = 0; + + public METALLICWORKFLOW = false; + public ROUGHNESSSTOREINMETALMAPALPHA = false; + public ROUGHNESSSTOREINMETALMAPGREEN = false; + public METALLNESSSTOREINMETALMAPBLUE = false; + public AOSTOREINMETALMAPRED = false; + public METALLIC_REFLECTANCE = false; + public METALLIC_REFLECTANCE_GAMMA = false; + public METALLIC_REFLECTANCEDIRECTUV = 0; + public METALLIC_REFLECTANCE_USE_ALPHA_ONLY = false; + public REFLECTANCE = false; + public REFLECTANCE_GAMMA = false; + public REFLECTANCEDIRECTUV = 0; + + 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 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; + 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; + + /** + * 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; + } +} + +/** + * 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 PBRMaterial2 extends PBRBaseMaterial { + /** + * PBRMaterial2TransparencyMode: No transparency mode, Alpha channel is not use. + */ + public static override readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; + + /** + * PBRMaterial2TransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. + */ + public static override readonly PBRMATERIAL_ALPHATEST = PBRBaseMaterial.PBRMATERIAL_ALPHATEST; + + /** + * PBRMaterial2TransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + */ + public static override readonly PBRMATERIAL_ALPHABLEND = PBRBaseMaterial.PBRMATERIAL_ALPHABLEND; + + /** + * PBRMaterial2TransparencyMode: 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 override readonly PBRMATERIAL_ALPHATESTANDBLEND = PBRBaseMaterial.PBRMATERIAL_ALPHATESTANDBLEND; + + /** + * Defines the default value of how much AO map is occluding the analytical lights + * (point spot...). + */ + public static override DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + + /** + * 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; + + /** + * This is a special control allowing the reduction of the specular highlights coming from the + * four lights of the scene. Those highlights may not be needed in full environment lighting. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public specularIntensity: number = 1.0; + + /** + * Debug Control allowing disabling the bump map on this material. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public disableBumpMap: boolean = false; + + /** + * AKA Diffuse Texture in standard nomenclature. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public albedoTexture: Nullable; + + /** + * OpenPBR Base Weight texture (multiplier to the diffuse and metal lobes). + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public baseWeightTexture: Nullable; + + /** + * OpenPBR Base Diffuse Roughness texture (roughness of the diffuse lobe). + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public baseDiffuseRoughnessTexture: Nullable; + + /** + * AKA Occlusion Texture in other nomenclature. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public ambientTexture: Nullable; + + /** + * AKA Occlusion Texture Intensity in other nomenclature. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public ambientTextureStrength: number = 1.0; + + /** + * Defines how much the AO map is occluding the analytical lights (point spot...). + * 1 means it completely occludes it + * 0 mean it has no impact + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public ambientTextureImpactOnAnalyticalLights: number = PBRMaterial2.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + + /** + * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") + public opacityTexture: Nullable; + + /** + * Stores the reflection values in a texture. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectionTexture: Nullable; + + /** + * Stores the emissive values in a texture. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public emissiveTexture: Nullable; + + /** + * AKA Specular texture in other nomenclature. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectivityTexture: Nullable; + + /** + * Used to switch from specular/glossiness to metallic/roughness workflow. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public metallicTexture: Nullable; + + /** + * Specifies the metallic scalar of the metallic/roughness workflow. + * Can also be used to scale the metalness values of the metallic texture. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public metallic: Nullable; + + /** + * Specifies the roughness scalar of the metallic/roughness workflow. + * Can also be used to scale the roughness values of the metallic texture. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public roughness: Nullable; + + /** + * In metallic workflow, specifies an F0 factor to help configuring the material F0. + * By default the indexOfrefraction is used to compute F0; + * + * This is used as a factor against the default reflectance at normal incidence to tweak it. + * + * F0 = defaultF0 * metallicF0Factor * metallicReflectanceColor; + * F90 = metallicReflectanceColor; + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public metallicF0Factor = 1; + + /** + * In metallic workflow, specifies an F0 color. + * By default the F90 is always 1; + * + * Please note that this factor is also used as a factor against the default reflectance at normal incidence. + * + * F0 = defaultF0_from_IOR * metallicF0Factor * metallicReflectanceColor + * F90 = metallicF0Factor; + */ + @serializeAsColor3() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public metallicReflectanceColor = Color3.White(); + + /** + * Specifies that only the A channel from metallicReflectanceTexture should be used. + * If false, both RGB and A channels will be used + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useOnlyMetallicFromMetallicReflectanceTexture = false; + + /** + * Defines to store metallicReflectanceColor in RGB and metallicF0Factor in A + * This is multiplied against the scalar values defined in the material. + * If useOnlyMetallicFromMetallicReflectanceTexture is true, don't use the RGB channels, only A + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public metallicReflectanceTexture: Nullable; + + /** + * Defines to store reflectanceColor in RGB + * This is multiplied against the scalar values defined in the material. + * If both reflectanceTexture and metallicReflectanceTexture textures are provided and useOnlyMetallicFromMetallicReflectanceTexture + * is false, metallicReflectanceTexture takes priority and reflectanceTexture is not used + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectanceTexture: Nullable; + + /** + * Used to enable roughness/glossiness fetch from a separate channel depending on the current mode. + * Gray Scale represents roughness in metallic mode and glossiness in specular mode. + */ + @serializeAsTexture() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public microSurfaceTexture: Nullable; + + /** + * 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; + + /** + * Stores the refracted light information in a texture. + */ + public get refractionTexture(): Nullable { + return this.subSurface.refractionTexture; + } + public set refractionTexture(value: Nullable) { + this.subSurface.refractionTexture = value; + if (value) { + this.subSurface.isRefractionEnabled = true; + } else if (!this.subSurface.linkRefractionWithTransparency) { + this.subSurface.isRefractionEnabled = false; + } + } + + /** + * The color of a material in ambient lighting. + */ + @serializeAsColor3("ambient") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public ambientColor = new Color3(0, 0, 0); + + /** + * AKA Diffuse Color in other nomenclature. + */ + @serializeAsColor3("albedo") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public albedoColor = new Color3(1, 1, 1); + + /** + * OpenPBR Base Weight (multiplier to the diffuse and metal lobes). + */ + @serialize("baseWeight") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public baseWeight = 1; + + /** + * OpenPBR Base Diffuse Roughness (roughness of the diffuse lobe). + */ + @serialize("baseDiffuseRoughness") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public baseDiffuseRoughness: Nullable; + + /** + * AKA Specular Color in other nomenclature. + */ + @serializeAsColor3("reflectivity") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectivityColor = new Color3(1, 1, 1); + + /** + * The color reflected from the material. + */ + @serializeAsColor3("reflection") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public reflectionColor = new Color3(1.0, 1.0, 1.0); + + /** + * The color emitted from the material. + */ + @serializeAsColor3("emissive") + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public emissiveColor = new Color3(0, 0, 0); + + /** + * AKA Glossiness in other nomenclature. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public microSurface = 1.0; + + /** + * Index of refraction of the material base layer. + * https://en.wikipedia.org/wiki/List_of_refractive_indices + * + * This does not only impact refraction but also the Base F0 of Dielectric Materials. + * + * From dielectric fresnel rules: F0 = square((iorT - iorI) / (iorT + iorI)) + */ + public get indexOfRefraction(): number { + return this.subSurface.indexOfRefraction; + } + public set indexOfRefraction(value: number) { + this.subSurface.indexOfRefraction = value; + } + + /** + * Controls if refraction needs to be inverted on Y. This could be useful for procedural texture. + */ + public get invertRefractionY(): boolean { + return this.subSurface.invertRefractionY; + } + public set invertRefractionY(value: boolean) { + this.subSurface.invertRefractionY = value; + } + + /** + * This parameters will make the material used its opacity to control how much it is refracting against not. + * Materials half opaque for instance using refraction could benefit from this control. + */ + public get linkRefractionWithTransparency(): boolean { + return this.subSurface.linkRefractionWithTransparency; + } + public set linkRefractionWithTransparency(value: boolean) { + this.subSurface.linkRefractionWithTransparency = value; + if (value) { + this.subSurface.isRefractionEnabled = true; + } + } + + /** + * 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 that the material will keep 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. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useSpecularOverAlpha = true; + + /** + * 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 roughness information in its alpha channel. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useRoughnessFromMetallicTextureAlpha = true; + + /** + * Specifies if the metallic texture contains the roughness information in its green channel. + * Needs useRoughnessFromMetallicTextureAlpha to be false. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useRoughnessFromMetallicTextureGreen = false; + + /** + * Specifies if the metallic texture contains the metallness information in its blue channel. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useMetallnessFromMetallicTextureBlue = 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; + } + } + } + + /** + * 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. + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsTexturesDirty") + public useRadianceOverAlpha = true; + + /** + * 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; + + /** + * 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 PBRMaterial2 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, forceGLSL); + + this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene()); + } + + /** + * @returns the name of this material class. + */ + public override getClassName(): string { + return "PBRMaterial2"; + } + + /** + * 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 diffuse 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 = ""): PBRMaterial2 { + const clone = SerializationHelper.Clone(() => new PBRMaterial2(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.PBRMaterial2"; + + 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 - PBRMaterial2 + */ + public static override Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial2 { + const material = SerializationHelper.Parse(() => new PBRMaterial2(source.name, scene), source, scene, rootUrl); + + if (source.stencil) { + material.stencil.parse(source.stencil, scene, rootUrl); + } + + Material._ParsePlugins(source, material, scene, rootUrl); + + // The code block below ensures backward compatibility with serialized materials before plugins are automatically serialized. + if (source.clearCoat) { + material.clearCoat.parse(source.clearCoat, scene, rootUrl); + } + if (source.anisotropy) { + material.anisotropy.parse(source.anisotropy, scene, rootUrl); + } + if (source.brdf) { + material.brdf.parse(source.brdf, scene, rootUrl); + } + if (source.sheen) { + material.sheen.parse(source.sheen, scene, rootUrl); + } + if (source.subSurface) { + material.subSurface.parse(source.subSurface, scene, rootUrl); + } + if (source.iridescence) { + material.iridescence.parse(source.iridescence, 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._breakShaderLoadedCheck2) { + return; + } + const defines = new PBRMaterial2Defines(this._eventInfo.defineNames); + const effect = this._prepareEffect2(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 PBRMaterial2Defines(this._eventInfo.defineNames); + } + + 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) { + if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + if (!this._albedoTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { + if (!this._baseWeightTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { + if (!this._baseDiffuseRoughnessTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { + if (!this._ambientTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { + if (!this._opacityTexture.isReadyOrNotBlocking()) { + return false; + } + } + + const reflectionTexture = this._getReflectionTexture2(); + 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 (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { + if (!this._emissiveTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (MaterialFlags.SpecularTextureEnabled) { + if (this._metallicTexture) { + if (!this._metallicTexture.isReadyOrNotBlocking()) { + return false; + } + } else if (this._reflectivityTexture) { + if (!this._reflectivityTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._metallicReflectanceTexture) { + if (!this._metallicReflectanceTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._reflectanceTexture) { + if (!this._reflectanceTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._microSurfaceTexture) { + if (!this._microSurfaceTexture.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("PBRMaterial2: Normals have been created for the mesh: " + mesh.name); + } + + const previousEffect = subMesh.effect; + const lightDisposed = defines._areLightsDisposed; + let effect = this._prepareEffect2(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; + } + + private _prepareEffect2( + mesh: AbstractMesh, + defines: PBRMaterial2Defines, + onCompiled: Nullable<(effect: Effect) => void> = null, + onError: Nullable<(effect: Effect, errors: string) => void> = null, + useInstances: Nullable = null, + useClipPlane: Nullable = null, + useThinInstances: boolean + ): Nullable { + this._prepareDefines2(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.AMBIENT) { + fallbacks.addFallback(fallbackRank++, "AMBIENT"); + } + + if (defines.EMISSIVE) { + fallbacks.addFallback(fallbackRank++, "EMISSIVE"); + } + + 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 = "pbr2"; + + const uniforms = [ + "world", + "view", + "viewProjection", + "vEyePosition", + "vLightsType", + "vAmbientColor", + "vAlbedoColor", + "baseWeight", + "baseDiffuseRoughness", + "vReflectivityColor", + "vMetallicReflectanceFactors", + "vEmissiveColor", + "visibility", + "vReflectionColor", + "vFogInfos", + "vFogColor", + "pointSize", + "vAlbedoInfos", + "vBaseWeightInfos", + "vBaseDiffuseRoughnessInfos", + "vAmbientInfos", + "vOpacityInfos", + "vReflectionInfos", + "vReflectionPosition", + "vReflectionSize", + "vEmissiveInfos", + "vReflectivityInfos", + "vReflectionFilteringInfo", + "vMetallicReflectanceInfos", + "vReflectanceInfos", + "vMicroSurfaceSamplerInfos", + "vBumpInfos", + "vLightmapInfos", + "mBones", + "albedoMatrix", + "baseWeightMatrix", + "baseDiffuseRoughnessMatrix", + "ambientMatrix", + "opacityMatrix", + "reflectionMatrix", + "emissiveMatrix", + "reflectivityMatrix", + "normalMatrix", + "microSurfaceSamplerMatrix", + "bumpMatrix", + "lightmapMatrix", + "metallicReflectanceMatrix", + "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", + "morphTargetTextureInfo", + "morphTargetTextureIndices", + "cameraInfo", + ]; + + const samplers = [ + "albedoSampler", + "baseWeightSampler", + "baseDiffuseRoughnessSampler", + "reflectivitySampler", + "ambientSampler", + "emissiveSampler", + "bumpSampler", + "lightmapSampler", + "opacitySampler", + "reflectionSampler", + "reflectionSamplerLow", + "reflectionSamplerHigh", + "irradianceSampler", + "microSurfaceSampler", + "environmentBrdfSampler", + "boneSampler", + "metallicReflectanceSampler", + "reflectanceSampler", + "morphTargets", + "oitDepthSampler", + "oitFrontColorSampler", + "icdfSampler", + "areaLightsLTC1Sampler", + "areaLightsLTC2Sampler", + ]; + + 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._shadersLoaded2 + ? undefined + : async () => { + if (this.shaderLanguage === ShaderLanguage.WGSL) { + await Promise.all([import("../../ShadersWGSL/pbr2.vertex"), import("../../ShadersWGSL/pbr2.fragment")]); + } else { + await Promise.all([import("../../Shaders/pbr2.vertex"), import("../../Shaders/pbr2.fragment")]); + } + + this._shadersLoaded2 = true; + }, + }, + engine + ); + + this._eventInfo.customCode = undefined; + + return effect; + } + + private _prepareDefines2( + mesh: AbstractMesh, + defines: PBRMaterial2Defines, + 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 = this.isMetallicWorkflow(); + 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.ALBEDODIRECTUV = 0; + defines.BASE_WEIGHTDIRECTUV = 0; + defines.BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; + defines.AMBIENTDIRECTUV = 0; + defines.OPACITYDIRECTUV = 0; + defines.EMISSIVEDIRECTUV = 0; + defines.REFLECTIVITYDIRECTUV = 0; + defines.MICROSURFACEMAPDIRECTUV = 0; + defines.METALLIC_REFLECTANCEDIRECTUV = 0; + defines.REFLECTANCEDIRECTUV = 0; + defines.BUMPDIRECTUV = 0; + defines.LIGHTMAPDIRECTUV = 0; + + if (engine.getCaps().textureLOD) { + defines.LODBASEDMICROSFURACE = true; + } + + if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + PrepareDefinesForMergedUV(this._albedoTexture, defines, "ALBEDO"); + defines.GAMMAALBEDO = this._albedoTexture.gammaSpace; + } else { + defines.ALBEDO = false; + } + + if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { + PrepareDefinesForMergedUV(this._baseWeightTexture, defines, "BASE_WEIGHT"); + } else { + defines.BASE_WEIGHT = false; + } + + if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { + PrepareDefinesForMergedUV(this._baseDiffuseRoughnessTexture, defines, "BASE_DIFFUSE_ROUGHNESS"); + } else { + defines.BASE_DIFFUSE_ROUGHNESS = false; + } + + if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { + PrepareDefinesForMergedUV(this._ambientTexture, defines, "AMBIENT"); + defines.AMBIENTINGRAYSCALE = this._useAmbientInGrayScale; + } else { + defines.AMBIENT = false; + } + + if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { + PrepareDefinesForMergedUV(this._opacityTexture, defines, "OPACITY"); + defines.OPACITYRGB = this._opacityTexture.getAlphaFromRGB; + } else { + defines.OPACITY = false; + } + + const reflectionTexture = this._getReflectionTexture2(); + 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; + } + + 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 (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { + PrepareDefinesForMergedUV(this._emissiveTexture, defines, "EMISSIVE"); + defines.GAMMAEMISSIVE = this._emissiveTexture.gammaSpace; + } else { + defines.EMISSIVE = false; + } + + if (MaterialFlags.SpecularTextureEnabled) { + if (this._metallicTexture) { + PrepareDefinesForMergedUV(this._metallicTexture, defines, "REFLECTIVITY"); + defines.ROUGHNESSSTOREINMETALMAPALPHA = this._useRoughnessFromMetallicTextureAlpha; + defines.ROUGHNESSSTOREINMETALMAPGREEN = !this._useRoughnessFromMetallicTextureAlpha && this._useRoughnessFromMetallicTextureGreen; + defines.METALLNESSSTOREINMETALMAPBLUE = this._useMetallnessFromMetallicTextureBlue; + defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed; + defines.REFLECTIVITY_GAMMA = false; + } else if (this._reflectivityTexture) { + PrepareDefinesForMergedUV(this._reflectivityTexture, defines, "REFLECTIVITY"); + defines.MICROSURFACEFROMREFLECTIVITYMAP = this._useMicroSurfaceFromReflectivityMapAlpha; + defines.MICROSURFACEAUTOMATIC = this._useAutoMicroSurfaceFromReflectivityMap; + defines.REFLECTIVITY_GAMMA = this._reflectivityTexture.gammaSpace; + } else { + defines.REFLECTIVITY = false; + } + + if (this._metallicReflectanceTexture || this._reflectanceTexture) { + defines.METALLIC_REFLECTANCE_USE_ALPHA_ONLY = this._useOnlyMetallicFromMetallicReflectanceTexture; + if (this._metallicReflectanceTexture) { + PrepareDefinesForMergedUV(this._metallicReflectanceTexture, defines, "METALLIC_REFLECTANCE"); + defines.METALLIC_REFLECTANCE_GAMMA = this._metallicReflectanceTexture.gammaSpace; + } else { + defines.METALLIC_REFLECTANCE = false; + } + if ( + this._reflectanceTexture && + (!this._metallicReflectanceTexture || (this._metallicReflectanceTexture && this._useOnlyMetallicFromMetallicReflectanceTexture)) + ) { + PrepareDefinesForMergedUV(this._reflectanceTexture, defines, "REFLECTANCE"); + defines.REFLECTANCE_GAMMA = this._reflectanceTexture.gammaSpace; + } else { + defines.REFLECTANCE = false; + } + } else { + defines.METALLIC_REFLECTANCE = false; + defines.REFLECTANCE = false; + } + + if (this._microSurfaceTexture) { + PrepareDefinesForMergedUV(this._microSurfaceTexture, defines, "MICROSURFACEMAP"); + } else { + defines.MICROSURFACEMAP = false; + } + } else { + defines.REFLECTIVITY = false; + defines.MICROSURFACEMAP = false; + } + + if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + PrepareDefinesForMergedUV(this._bumpTexture, defines, "BUMP"); + + if (this._useParallax && this._albedoTexture && 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); + defines.ALPHAFRESNEL = this._useAlphaFresnel || this._useLinearAlphaFresnel; + defines.LINEARALPHAFRESNEL = this._useLinearAlphaFresnel; + } + + 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, false); + defines.UNLIT = this._unlit2 || ((this.pointsCloud || this.wireframe) && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)); + defines.DEBUGMODE = this._debugMode2; + } + + // 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); + } + + /** + * Returns the texture used for reflections. + * @returns - Reflection texture if present. Otherwise, returns the environment texture. + */ + private _getReflectionTexture2(): Nullable { + if (this._reflectionTexture) { + return this._reflectionTexture; + } + + return this.getScene().environmentTexture; + } + + private _shadersLoaded2 = false; + + /** + * If set to true, no lighting calculations will be applied. + */ + private _unlit2 = false; + + private _debugMode2 = 0; + + private _breakShaderLoadedCheck2 = false; +} + +RegisterClass("BABYLON.PBRMaterial2", PBRMaterial2); diff --git a/packages/dev/core/src/Shaders/pbr2.fragment.fx b/packages/dev/core/src/Shaders/pbr2.fragment.fx new file mode 100644 index 00000000000..ac621aa07b2 --- /dev/null +++ b/packages/dev/core/src/Shaders/pbr2.fragment.fx @@ -0,0 +1,692 @@ +#define PBR_FRAGMENT_SHADER + +#define CUSTOM_FRAGMENT_EXTENSION + +#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#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__pbrFragment> + +#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 +#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 ALBEDO + vec4 albedoTexture = texture2D(albedoSampler, vAlbedoUV + uvOffset); +#endif + +#ifdef BASE_WEIGHT + vec4 baseWeightTexture = 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( + vAlbedoColor + #ifdef ALBEDO + , albedoTexture + , vAlbedoInfos + #endif + , baseWeight + #ifdef BASE_WEIGHT + , baseWeightTexture + , 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 + + // _____________________________ AO _______________________________ + ambientOcclusionOutParams aoOut; + +#ifdef AMBIENT + vec3 ambientOcclusionColorMap = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb; +#endif + + aoOut = ambientOcclusionBlock( + #ifdef AMBIENT + ambientOcclusionColorMap, + vAmbientInfos + #endif + ); + + #include + +#ifdef UNLIT + vec3 diffuseBase = vec3(1., 1., 1.); +#else // !UNLIT + + // _____________________________ Reflectivity _______________________________ + vec3 baseColor = surfaceAlbedo; + + reflectivityOutParams reflectivityOut; + +#if defined(REFLECTIVITY) + vec4 surfaceMetallicOrReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset); + vec4 baseReflectivity = surfaceMetallicOrReflectivityColorMap; + #ifndef METALLICWORKFLOW + #ifdef REFLECTIVITY_GAMMA + surfaceMetallicOrReflectivityColorMap = toLinearSpace(surfaceMetallicOrReflectivityColorMap); + #endif + surfaceMetallicOrReflectivityColorMap.rgb *= vReflectivityInfos.y; + #endif +#endif + +#if defined(MICROSURFACEMAP) + vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y; +#endif + +#ifdef METALLICWORKFLOW + vec4 metallicReflectanceFactors = vMetallicReflectanceFactors; + #ifdef REFLECTANCE + vec4 reflectanceFactorsMap = texture2D(reflectanceSampler, vReflectanceUV + uvOffset); + #ifdef REFLECTANCE_GAMMA + reflectanceFactorsMap = toLinearSpace(reflectanceFactorsMap); + #endif + + metallicReflectanceFactors.rgb *= reflectanceFactorsMap.rgb; + #endif + #ifdef METALLIC_REFLECTANCE + vec4 metallicReflectanceFactorsMap = texture2D(metallicReflectanceSampler, vMetallicReflectanceUV + uvOffset); + #ifdef METALLIC_REFLECTANCE_GAMMA + metallicReflectanceFactorsMap = toLinearSpace(metallicReflectanceFactorsMap); + #endif + + #ifndef METALLIC_REFLECTANCE_USE_ALPHA_ONLY + metallicReflectanceFactors.rgb *= metallicReflectanceFactorsMap.rgb; + #endif + metallicReflectanceFactors.a *= metallicReflectanceFactorsMap.a; + #endif +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + float baseDiffuseRoughnessTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; +#endif + + reflectivityOut = reflectivityBlock( + vReflectivityColor + #ifdef METALLICWORKFLOW + , surfaceAlbedo + , metallicReflectanceFactors + #endif + , baseDiffuseRoughness + #ifdef BASE_DIFFUSE_ROUGHNESS + , baseDiffuseRoughnessTexture + , vBaseDiffuseRoughnessInfos + #endif + #ifdef REFLECTIVITY + , vReflectivityInfos + , surfaceMetallicOrReflectivityColorMap + #endif + #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + , aoOut.ambientOcclusionColor + #endif + #ifdef MICROSURFACEMAP + , microSurfaceTexel + #endif + #ifdef DETAIL + , detailColor + , vDetailInfos + #endif + ); + + float microSurface = reflectivityOut.microSurface; + float roughness = reflectivityOut.roughness; + float diffuseRoughness = reflectivityOut.diffuseRoughness; + + #ifdef METALLICWORKFLOW + surfaceAlbedo = reflectivityOut.surfaceAlbedo; + #endif + #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; + #endif + + // _____________________________ Alpha Fresnel ___________________________________ + #ifdef ALPHAFRESNEL + #if defined(ALPHATEST) || defined(ALPHABLEND) + alphaFresnelOutParams alphaFresnelOut; + + alphaFresnelOut = alphaFresnelBlock( + normalW, + viewDirectionW, + alpha, + microSurface + ); + + alpha = alphaFresnelOut.alpha; + #endif + #endif + + // _____________________________ Compute Geometry info _________________________________ + #include + + // _____________________________ Anisotropy _______________________________________ + #ifdef ANISOTROPIC + anisotropicOutParams anisotropicOut; + + #ifdef ANISOTROPIC_TEXTURE + vec3 anisotropyMapData = texture2D(anisotropySampler, vAnisotropyUV + uvOffset).rgb * vAnisotropyInfos.y; + #endif + + anisotropicOut = anisotropicBlock( + vAnisotropy, + roughness, + #ifdef ANISOTROPIC_TEXTURE + anisotropyMapData, + #endif + TBN, + normalW, + viewDirectionW + ); + #endif + + // _____________________________ 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 + , baseColor + ); + #else + #define CUSTOM_REFLECTION + #endif + #endif + + // ___________________ Compute Reflectance aka R0 F0 info _________________________ + #include + + // ________________________________ Sheen ______________________________ + #ifdef SHEEN + sheenOutParams sheenOut; + + #ifdef SHEEN_TEXTURE + vec4 sheenMapData = texture2D(sheenSampler, vSheenUV + uvOffset); + #endif + #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) + vec4 sheenMapRoughnessData = texture2D(sheenRoughnessSampler, vSheenRoughnessUV + uvOffset) * vSheenInfos.w; + #endif + + sheenOut = sheenBlock( + vSheenColor + #ifdef SHEEN_ROUGHNESS + , vSheenRoughness + #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) + , sheenMapRoughnessData + #endif + #endif + , roughness + #ifdef SHEEN_TEXTURE + , sheenMapData + , vSheenInfos.y + #endif + , reflectanceF0 + #ifdef SHEEN_LINKWITHALBEDO + , baseColor + , surfaceAlbedo + #endif + #ifdef ENVIRONMENTBRDF + , NdotV + , environmentBrdf + #endif + #if defined(REFLECTION) && defined(ENVIRONMENTBRDF) + , AARoughnessFactors + , vReflectionMicrosurfaceInfos + , vReflectionInfos + , vReflectionColor + , vLightingIntensity + , reflectionSampler + , reflectionOut.reflectionCoords + , NdotVUnclamped + #ifndef LODBASEDMICROSFURACE + , reflectionSamplerLow + , reflectionSamplerHigh + #endif + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + #if !defined(REFLECTIONMAP_SKYBOX) && defined(RADIANCEOCCLUSION) + , seo + #endif + #if !defined(REFLECTIONMAP_SKYBOX) && defined(HORIZONOCCLUSION) && defined(BUMP) && defined(REFLECTIONMAP_3D) + , eho + #endif + #endif + ); + + #ifdef SHEEN_LINKWITHALBEDO + surfaceAlbedo = sheenOut.surfaceAlbedo; + #endif + #endif + + // _____________ Shared Iridescence and Clear Coat data _________________ + #ifdef CLEARCOAT + #ifdef CLEARCOAT_TEXTURE + vec2 clearCoatMapData = texture2D(clearCoatSampler, vClearCoatUV + uvOffset).rg * vClearCoatInfos.y; + #endif + #endif + + // _____________________________ Iridescence ____________________________ + #ifdef IRIDESCENCE + iridescenceOutParams iridescenceOut; + + #ifdef IRIDESCENCE_TEXTURE + vec2 iridescenceMapData = texture2D(iridescenceSampler, vIridescenceUV + uvOffset).rg * vIridescenceInfos.y; + #endif + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + vec2 iridescenceThicknessMapData = texture2D(iridescenceThicknessSampler, vIridescenceThicknessUV + uvOffset).rg * vIridescenceInfos.w; + #endif + + iridescenceOut = iridescenceBlock( + vIridescenceParams + , NdotV + , specularEnvironmentR0 + #ifdef IRIDESCENCE_TEXTURE + , iridescenceMapData + #endif + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + , iridescenceThicknessMapData + #endif + #ifdef CLEARCOAT + , NdotVUnclamped + , vClearCoatParams + #ifdef CLEARCOAT_TEXTURE + , clearCoatMapData + #endif + #endif + ); + + float iridescenceIntensity = iridescenceOut.iridescenceIntensity; + specularEnvironmentR0 = iridescenceOut.specularEnvironmentR0; + #endif + + // _____________________________ Clear Coat ____________________________ + clearcoatOutParams clearcoatOut; + + #ifdef CLEARCOAT + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) + vec4 clearCoatMapRoughnessData = texture2D(clearCoatRoughnessSampler, vClearCoatRoughnessUV + uvOffset) * vClearCoatInfos.w; + #endif + + #if defined(CLEARCOAT_TINT) && defined(CLEARCOAT_TINT_TEXTURE) + vec4 clearCoatTintMapData = texture2D(clearCoatTintSampler, vClearCoatTintUV + uvOffset); + #endif + + #ifdef CLEARCOAT_BUMP + vec4 clearCoatBumpMapData = texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset); + #endif + + clearcoatOut = clearcoatBlock( + vPositionW + , geometricNormalW + , viewDirectionW + , vClearCoatParams + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) + , clearCoatMapRoughnessData + #endif + , specularEnvironmentR0 + #ifdef CLEARCOAT_TEXTURE + , clearCoatMapData + #endif + #ifdef CLEARCOAT_TINT + , vClearCoatTintParams + , clearCoatColorAtDistance + , vClearCoatRefractionParams + #ifdef CLEARCOAT_TINT_TEXTURE + , clearCoatTintMapData + #endif + #endif + #ifdef CLEARCOAT_BUMP + , vClearCoatBumpInfos + , clearCoatBumpMapData + , vClearCoatBumpUV + #if defined(TANGENT) && defined(NORMAL) + , vTBN + #else + , vClearCoatTangentSpaceParams + #endif + #ifdef OBJECTSPACE_NORMALMAP + , normalMatrix + #endif + #endif + #if defined(FORCENORMALFORWARD) && defined(NORMAL) + , faceNormal + #endif + #ifdef REFLECTION + , vReflectionMicrosurfaceInfos + , vReflectionInfos + , vReflectionColor + , vLightingIntensity + , reflectionSampler + #ifndef LODBASEDMICROSFURACE + , reflectionSamplerLow + , reflectionSamplerHigh + #endif + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + #endif + #if defined(CLEARCOAT_BUMP) || defined(TWOSIDEDLIGHTING) + , (gl_FrontFacing ? 1. : -1.) + #endif + ); + #else + clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0; + #endif + + // _________________________ Specular Environment Reflectance __________________________ + #include + + // ___________________________________ SubSurface ______________________________________ + subSurfaceOutParams subSurfaceOut; + + #ifdef SUBSURFACE + #ifdef SS_THICKNESSANDMASK_TEXTURE + vec4 thicknessMap = texture2D(thicknessSampler, vThicknessUV + uvOffset); + #endif + + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + vec4 refractionIntensityMap = texture2D(refractionIntensitySampler, vRefractionIntensityUV + uvOffset); + #endif + + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + vec4 translucencyIntensityMap = texture2D(translucencyIntensitySampler, vTranslucencyIntensityUV + uvOffset); + #endif + + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + vec4 translucencyColorMap = texture2D(translucencyColorSampler, vTranslucencyColorUV + uvOffset); + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE_GAMMA + translucencyColorMap = toLinearSpace(translucencyColorMap); + #endif + #endif + + #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION + vec3 vSpecularEnvironmentReflectance = vec3(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b))); + #endif + + subSurfaceOut = subSurfaceBlock( + vSubSurfaceIntensity + , vThicknessParam + , vTintColor + , normalW + #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION + , vSpecularEnvironmentReflectance + #else + , baseSpecularEnvironmentReflectance + #endif + #ifdef SS_THICKNESSANDMASK_TEXTURE + , thicknessMap + #endif + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + , refractionIntensityMap + #endif + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + , translucencyIntensityMap + #endif + #ifdef REFLECTION + #ifdef SS_TRANSLUCENCY + , reflectionMatrix + #ifdef USESPHERICALFROMREFLECTIONMAP + #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) + , reflectionOut.irradianceVector + #endif + #if defined(REALTIME_FILTERING) + , reflectionSampler + , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + #endif + #endif + #endif + #ifdef USEIRRADIANCEMAP + , irradianceSampler + #endif + #endif + #endif + #if defined(SS_REFRACTION) || defined(SS_TRANSLUCENCY) + , surfaceAlbedo + #endif + #ifdef SS_REFRACTION + , vPositionW + , viewDirectionW + , view + , vRefractionInfos + , refractionMatrix + , vRefractionMicrosurfaceInfos + , vLightingIntensity + #ifdef SS_LINKREFRACTIONTOTRANSPARENCY + , alpha + #endif + #ifdef SS_LODINREFRACTIONALPHA + , NdotVUnclamped + #endif + #ifdef SS_LINEARSPECULARREFRACTION + , roughness + #endif + , alphaG + , refractionSampler + #ifndef LODBASEDMICROSFURACE + , refractionSamplerLow + , refractionSamplerHigh + #endif + #ifdef ANISOTROPIC + , anisotropicOut + #endif + #ifdef REALTIME_FILTERING + , vRefractionFilteringInfo + #endif + #ifdef SS_USE_LOCAL_REFRACTIONMAP_CUBIC + , vRefractionPosition + , vRefractionSize + #endif + #ifdef SS_DISPERSION + , dispersion + #endif + #endif + #ifdef SS_TRANSLUCENCY + , vDiffusionDistance + , vTranslucencyColor + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + , translucencyColorMap + #endif + #endif + ); + + #ifdef SS_REFRACTION + surfaceAlbedo = subSurfaceOut.surfaceAlbedo; + #ifdef SS_LINKREFRACTIONTOTRANSPARENCY + alpha = subSurfaceOut.alpha; + #endif + #endif + #else + subSurfaceOut.specularEnvironmentReflectance = colorSpecularEnvironmentReflectance; + #endif + + // _____________________________ Direct Lighting Info __________________________________ + #include + + #include[0..maxSimultaneousLights] + + // _____________________________ Compute Final Lit Components ________________________ + #include +#endif // !UNLIT + + #include + + #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/pbr2.vertex.fx b/packages/dev/core/src/Shaders/pbr2.vertex.fx new file mode 100644 index 00000000000..778fa33de08 --- /dev/null +++ b/packages/dev/core/src/Shaders/pbr2.vertex.fx @@ -0,0 +1,312 @@ +#define PBR_VERTEX_SHADER + +#define CUSTOM_VERTEX_EXTENSION + +precision highp float; + +#include<__decl__pbrVertex> + +#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_,ALBEDO,_VARYINGNAME_,Albedo) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) +#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient) +#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) +#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) +#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity) +#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler) +#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance) +#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance) +#include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy) +#endif + +#ifdef SUBSURFACE + #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness) + #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor) +#endif + +// 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 + +#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)) * baseDiffuseRoughness); + 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_,ALBEDO,_VARYINGNAME_,Albedo,_MATRIXNAME_,albedo,_INFONAME_,AlbedoInfos.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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) + #include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_MATRIXNAME_,ambient,_INFONAME_,AmbientInfos.x) + #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) + #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) + #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) + #include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_MATRIXNAME_,reflectivity,_INFONAME_,ReflectivityInfos.x) + #include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_MATRIXNAME_,microSurfaceSampler,_INFONAME_,MicroSurfaceSamplerInfos.x) + #include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_MATRIXNAME_,metallicReflectance,_INFONAME_,MetallicReflectanceInfos.x) + #include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_MATRIXNAME_,reflectance,_INFONAME_,ReflectanceInfos.x) + #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) + #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_MATRIXNAME_,clearCoat,_INFONAME_,ClearCoatInfos.x) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness,_MATRIXNAME_,clearCoatRoughness,_INFONAME_,ClearCoatInfos.z) + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_MATRIXNAME_,clearCoatBump,_INFONAME_,ClearCoatBumpInfos.x) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_MATRIXNAME_,clearCoatTint,_INFONAME_,ClearCoatTintInfos.x) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_MATRIXNAME_,iridescence,_INFONAME_,IridescenceInfos.x) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_MATRIXNAME_,iridescenceThickness,_INFONAME_,IridescenceInfos.z) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_MATRIXNAME_,sheen,_INFONAME_,SheenInfos.x) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness,_MATRIXNAME_,sheenRoughness,_INFONAME_,SheenInfos.z) + +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_MATRIXNAME_,anisotropy,_INFONAME_,AnisotropyInfos.x) +#endif + +#ifdef SUBSURFACE + #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness,_MATRIXNAME_,thickness,_INFONAME_,ThicknessInfos.x) + #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_MATRIXNAME_,refractionIntensity,_INFONAME_,RefractionIntensityInfos.x) + #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_MATRIXNAME_,translucencyIntensity,_INFONAME_,TranslucencyIntensityInfos.x) + #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_MATRIXNAME_,translucencyColor,_INFONAME_,TranslucencyColorInfos.x) +#endif + + // 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/pbr2.fragment.fx b/packages/dev/core/src/ShadersWGSL/pbr2.fragment.fx new file mode 100644 index 00000000000..91bae999b44 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/pbr2.fragment.fx @@ -0,0 +1,688 @@ +#define PBR_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 +#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 ALBEDO + var albedoTexture: vec4f = textureSample(albedoSampler, albedoSamplerSampler, fragmentInputs.vAlbedoUV + uvOffset); +#endif + +#ifdef BASE_WEIGHT + var baseWeightTexture: 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.vAlbedoColor + #ifdef ALBEDO + , albedoTexture + , uniforms.vAlbedoInfos + #endif + , uniforms.baseWeight + #ifdef BASE_WEIGHT + , baseWeightTexture + , 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 + var ambientOcclusionColorMap: vec3f = textureSample(ambientSampler, ambientSamplerSampler, fragmentInputs.vAmbientUV + uvOffset).rgb; +#endif + + aoOut = ambientOcclusionBlock( + #ifdef AMBIENT + ambientOcclusionColorMap, + uniforms.vAmbientInfos + #endif + ); + + #include + +#ifdef UNLIT + var diffuseBase: vec3f = vec3f(1., 1., 1.); +#else + + // _____________________________ Reflectivity _______________________________ + var baseColor: vec3f = surfaceAlbedo; + + var reflectivityOut: reflectivityOutParams; + +#if defined(REFLECTIVITY) + var surfaceMetallicOrReflectivityColorMap: vec4f = textureSample(reflectivitySampler, reflectivitySamplerSampler, fragmentInputs.vReflectivityUV + uvOffset); + var baseReflectivity: vec4f = surfaceMetallicOrReflectivityColorMap; + #ifndef METALLICWORKFLOW + #ifdef REFLECTIVITY_GAMMA + surfaceMetallicOrReflectivityColorMap = toLinearSpaceVec4(surfaceMetallicOrReflectivityColorMap); + #endif + surfaceMetallicOrReflectivityColorMap = vec4f(surfaceMetallicOrReflectivityColorMap.rgb * uniforms.vReflectivityInfos.y, surfaceMetallicOrReflectivityColorMap.a); + #endif +#endif + +#if defined(MICROSURFACEMAP) + var microSurfaceTexel: vec4f = textureSample(microSurfaceSampler, microSurfaceSamplerSampler, fragmentInputs.vMicroSurfaceSamplerUV + uvOffset) * uniforms.vMicroSurfaceSamplerInfos.y; +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + var baseDiffuseRoughnessTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, fragmentInputs.vBaseDiffuseRoughnessUV + uvOffset).x; +#endif + +#ifdef METALLICWORKFLOW + var metallicReflectanceFactors: vec4f = uniforms.vMetallicReflectanceFactors; + #ifdef REFLECTANCE + var reflectanceFactorsMap: vec4f = textureSample(reflectanceSampler, reflectanceSamplerSampler, fragmentInputs.vReflectanceUV + uvOffset); + #ifdef REFLECTANCE_GAMMA + reflectanceFactorsMap = toLinearSpaceVec4(reflectanceFactorsMap); + #endif + + metallicReflectanceFactors = vec4f(metallicReflectanceFactors.rgb * reflectanceFactorsMap.rgb, metallicReflectanceFactors.a); + #endif + #ifdef METALLIC_REFLECTANCE + var metallicReflectanceFactorsMap: vec4f = textureSample(metallicReflectanceSampler, metallicReflectanceSamplerSampler, fragmentInputs.vMetallicReflectanceUV + uvOffset); + #ifdef METALLIC_REFLECTANCE_GAMMA + metallicReflectanceFactorsMap = toLinearSpaceVec4(metallicReflectanceFactorsMap); + #endif + + #ifndef METALLIC_REFLECTANCE_USE_ALPHA_ONLY + metallicReflectanceFactors = vec4f(metallicReflectanceFactors.rgb * metallicReflectanceFactorsMap.rgb, metallicReflectanceFactors.a); + #endif + metallicReflectanceFactors.a *= metallicReflectanceFactorsMap.a; + #endif +#endif + + reflectivityOut = reflectivityBlock( + uniforms.vReflectivityColor + #ifdef METALLICWORKFLOW + , surfaceAlbedo + , metallicReflectanceFactors + #endif + , uniforms.baseDiffuseRoughness + #ifdef BASE_DIFFUSE_ROUGHNESS + , baseDiffuseRoughnessTexture + , uniforms.vBaseDiffuseRoughnessInfos + #endif + #ifdef REFLECTIVITY + , uniforms.vReflectivityInfos + , surfaceMetallicOrReflectivityColorMap + #endif + #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + , aoOut.ambientOcclusionColor + #endif + #ifdef MICROSURFACEMAP + , microSurfaceTexel + #endif + #ifdef DETAIL + , detailColor + , uniforms.vDetailInfos + #endif + ); + + var microSurface: f32 = reflectivityOut.microSurface; + var roughness: f32 = reflectivityOut.roughness; + var diffuseRoughness: f32 = reflectivityOut.diffuseRoughness; + + #ifdef METALLICWORKFLOW + surfaceAlbedo = reflectivityOut.surfaceAlbedo; + #endif + #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; + #endif + + // _____________________________ Alpha Fresnel ___________________________________ + #ifdef ALPHAFRESNEL + #if defined(ALPHATEST) || defined(ALPHABLEND) + var alphaFresnelOut: alphaFresnelOutParams; + + alphaFresnelOut = alphaFresnelBlock( + normalW, + viewDirectionW, + alpha, + microSurface + ); + + alpha = alphaFresnelOut.alpha; + #endif + #endif + + // _____________________________ Compute Geometry info _________________________________ + #include + + // _____________________________ Anisotropy _______________________________________ + #ifdef ANISOTROPIC + var anisotropicOut: anisotropicOutParams; + + #ifdef ANISOTROPIC_TEXTURE + var anisotropyMapData: vec3f = textureSample(anisotropySampler, anisotropySamplerSampler, fragmentInputs.vAnisotropyUV + uvOffset).rgb * uniforms.vAnisotropyInfos.y; + #endif + + anisotropicOut = anisotropicBlock( + uniforms.vAnisotropy, + roughness, + #ifdef ANISOTROPIC_TEXTURE + anisotropyMapData, + #endif + TBN, + normalW, + viewDirectionW + ); + #endif + + // _____________________________ 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 + #ifdef LINEARSPECULARREFLECTION + , roughness + #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 _________________________ + #include + + // ________________________________ Sheen ______________________________ + #ifdef SHEEN + var sheenOut: sheenOutParams; + + #ifdef SHEEN_TEXTURE + var sheenMapData: vec4f = textureSample(sheenSampler, sheenSamplerSampler, fragmentInputs.vSheenUV + uvOffset); + #endif + #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) + var sheenMapRoughnessData: vec4f = textureSample(sheenRoughnessSampler, sheenRoughnessSamplerSampler, fragmentInputs.vSheenRoughnessUV + uvOffset) * uniforms.vSheenInfos.w; + #endif + + sheenOut = sheenBlock( + uniforms.vSheenColor + #ifdef SHEEN_ROUGHNESS + , uniforms.vSheenRoughness + #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) + , sheenMapRoughnessData + #endif + #endif + , roughness + #ifdef SHEEN_TEXTURE + , sheenMapData + , uniforms.vSheenInfos.y + #endif + , reflectanceF0 + #ifdef SHEEN_LINKWITHALBEDO + , baseColor + , surfaceAlbedo + #endif + #ifdef ENVIRONMENTBRDF + , NdotV + , environmentBrdf + #endif + #if defined(REFLECTION) && defined(ENVIRONMENTBRDF) + , AARoughnessFactors + , uniforms.vReflectionMicrosurfaceInfos + , uniforms.vReflectionInfos + , uniforms.vReflectionColor + , uniforms.vLightingIntensity + , reflectionSampler + , reflectionSamplerSampler + , reflectionOut.reflectionCoords + , NdotVUnclamped + #ifndef LODBASEDMICROSFURACE + , reflectionLowSampler + , reflectionLowSamplerSampler + , reflectionHighSampler + , reflectionHighSamplerSampler + #endif + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #endif + #if !defined(REFLECTIONMAP_SKYBOX) && defined(RADIANCEOCCLUSION) + , seo + #endif + #if !defined(REFLECTIONMAP_SKYBOX) && defined(HORIZONOCCLUSION) && defined(BUMP) && defined(REFLECTIONMAP_3D) + , eho + #endif + #endif + ); + + #ifdef SHEEN_LINKWITHALBEDO + surfaceAlbedo = sheenOut.surfaceAlbedo; + #endif + #endif + + // _____________ Shared Iridescence and Clear Coat data _________________ + #ifdef CLEARCOAT + #ifdef CLEARCOAT_TEXTURE + var clearCoatMapData: vec2f = textureSample(clearCoatSampler, clearCoatSamplerSampler, fragmentInputs.vClearCoatUV + uvOffset).rg * uniforms.vClearCoatInfos.y; + #endif + #endif + + // _____________________________ Iridescence ____________________________ + #ifdef IRIDESCENCE + var iridescenceOut: iridescenceOutParams; + + #ifdef IRIDESCENCE_TEXTURE + var iridescenceMapData: vec2f = textureSample(iridescenceSampler, iridescenceSamplerSampler, fragmentInputs.vIridescenceUV + uvOffset).rg * uniforms.vIridescenceInfos.y; + #endif + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + var iridescenceThicknessMapData: vec2f = textureSample(iridescenceThicknessSampler, iridescenceThicknessSamplerSampler, fragmentInputs.vIridescenceThicknessUV + uvOffset).rg * uniforms.vIridescenceInfos.w; + #endif + + iridescenceOut = iridescenceBlock( + uniforms.vIridescenceParams + , NdotV + , specularEnvironmentR0 + #ifdef IRIDESCENCE_TEXTURE + , iridescenceMapData + #endif + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + , iridescenceThicknessMapData + #endif + #ifdef CLEARCOAT + , NdotVUnclamped + , uniforms.vClearCoatParams + #ifdef CLEARCOAT_TEXTURE + , clearCoatMapData + #endif + #endif + ); + + var iridescenceIntensity: f32 = iridescenceOut.iridescenceIntensity; + specularEnvironmentR0 = iridescenceOut.specularEnvironmentR0; + #endif + + // _____________________________ Clear Coat ____________________________ + var clearcoatOut: clearcoatOutParams; + + #ifdef CLEARCOAT + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) + var clearCoatMapRoughnessData: vec4f = textureSample(clearCoatRoughnessSampler, clearCoatRoughnessSamplerSampler, fragmentInputs.vClearCoatRoughnessUV + uvOffset) * uniforms.vClearCoatInfos.w; + #endif + + #if defined(CLEARCOAT_TINT) && defined(CLEARCOAT_TINT_TEXTURE) + var clearCoatTintMapData: vec4f = textureSample(clearCoatTintSampler, clearCoatTintSamplerSampler, fragmentInputs.vClearCoatTintUV + uvOffset); + #endif + + #ifdef CLEARCOAT_BUMP + var clearCoatBumpMapData: vec4f = textureSample(clearCoatBumpSampler, clearCoatBumpSamplerSampler, fragmentInputs.vClearCoatBumpUV + uvOffset); + #endif + + clearcoatOut = clearcoatBlock( + fragmentInputs.vPositionW + , geometricNormalW + , viewDirectionW + , uniforms.vClearCoatParams + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) + , clearCoatMapRoughnessData + #endif + , specularEnvironmentR0 + #ifdef CLEARCOAT_TEXTURE + , clearCoatMapData + #endif + #ifdef CLEARCOAT_TINT + , uniforms.vClearCoatTintParams + , uniforms.clearCoatColorAtDistance + , uniforms.vClearCoatRefractionParams + #ifdef CLEARCOAT_TINT_TEXTURE + , clearCoatTintMapData + #endif + #endif + #ifdef CLEARCOAT_BUMP + , uniforms.vClearCoatBumpInfos + , clearCoatBumpMapData + , fragmentInputs.vClearCoatBumpUV + #if defined(TANGENT) && defined(NORMAL) + , mat3x3(input.vTBN0, input.vTBN1, input.vTBN2) + #else + , uniforms.vClearCoatTangentSpaceParams + #endif + #ifdef OBJECTSPACE_NORMALMAP + , uniforms.normalMatrix + #endif + #endif + #if defined(FORCENORMALFORWARD) && defined(NORMAL) + , faceNormal + #endif + #ifdef REFLECTION + , uniforms.vReflectionMicrosurfaceInfos + , uniforms.vReflectionInfos + , uniforms.vReflectionColor + , uniforms.vLightingIntensity + , reflectionSampler + , reflectionSamplerSampler + #ifndef LODBASEDMICROSFURACE + , reflectionLowSampler + , reflectionLowSamplerSampler + , reflectionHighSampler + , reflectionHighSamplerSampler + #endif + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #endif + #endif + #if defined(CLEARCOAT_BUMP) || defined(TWOSIDEDLIGHTING) + , select(-1., 1., fragmentInputs.frontFacing) + #endif + ); + #else + clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0; + #endif + + // _________________________ Specular Environment Reflectance __________________________ + #include + + // ___________________________________ SubSurface ______________________________________ + var subSurfaceOut: subSurfaceOutParams; + + #ifdef SUBSURFACE + #ifdef SS_THICKNESSANDMASK_TEXTURE + var thicknessMap: vec4f = textureSample(thicknessSampler, thicknessSamplerSampler, fragmentInputs.vThicknessUV + uvOffset); + #endif + + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + var refractionIntensityMap: vec4f = textureSample(refractionIntensitySampler, refractionIntensitySamplerSampler, fragmentInputs.vRefractionIntensityUV + uvOffset); + #endif + + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + var translucencyIntensityMap: vec4f = textureSample(translucencyIntensitySampler, translucencyIntensitySamplerSampler, fragmentInputs.vTranslucencyIntensityUV + uvOffset); + #endif + + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + var translucencyColorMap: vec4f = textureSample(translucencyColorSampler, translucencyColorSamplerSampler, fragmentInputs.vTranslucencyColorUV + uvOffset); + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE_GAMMA + translucencyColorMap = toLinearSpaceVec4(translucencyColorMap); + #endif + #endif + + subSurfaceOut = subSurfaceBlock( + uniforms.vSubSurfaceIntensity + , uniforms.vThicknessParam + , uniforms.vTintColor + , normalW + #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION + , vec3f(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b))) + #else + , baseSpecularEnvironmentReflectance + #endif + #ifdef SS_THICKNESSANDMASK_TEXTURE + , thicknessMap + #endif + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + , refractionIntensityMap + #endif + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + , translucencyIntensityMap + #endif + #ifdef REFLECTION + #ifdef SS_TRANSLUCENCY + , uniforms.reflectionMatrix + #ifdef USESPHERICALFROMREFLECTIONMAP + #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) + , reflectionOut.irradianceVector + #endif + #if defined(REALTIME_FILTERING) + , reflectionSampler + , reflectionSamplerSampler + , uniforms.vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + , icdfSamplerSampler + #endif + #endif + #endif + #ifdef USEIRRADIANCEMAP + , irradianceSampler + , irradianceSamplerSampler + #endif + #endif + #endif + #if defined(SS_REFRACTION) || defined(SS_TRANSLUCENCY) + , surfaceAlbedo + #endif + #ifdef SS_REFRACTION + , fragmentInputs.vPositionW + , viewDirectionW + , scene.view + , uniforms.vRefractionInfos + , uniforms.refractionMatrix + , uniforms.vRefractionMicrosurfaceInfos + , uniforms.vLightingIntensity + #ifdef SS_LINKREFRACTIONTOTRANSPARENCY + , alpha + #endif + #ifdef SS_LODINREFRACTIONALPHA + , NdotVUnclamped + #endif + #ifdef SS_LINEARSPECULARREFRACTION + , roughness + #endif + , alphaG + , refractionSampler + , refractionSamplerSampler + #ifndef LODBASEDMICROSFURACE + , refractionLowSampler + , refractionLowSamplerSampler + , refractionHighSampler + , refractionHighSamplerSampler + #endif + #ifdef ANISOTROPIC + , anisotropicOut + #endif + #ifdef REALTIME_FILTERING + , uniforms.vRefractionFilteringInfo + #endif + #ifdef SS_USE_LOCAL_REFRACTIONMAP_CUBIC + , uniforms.vRefractionPosition + , uniforms.vRefractionSize + #endif + #ifdef SS_DISPERSION + , dispersion + #endif + #endif + #ifdef SS_TRANSLUCENCY + , uniforms.vDiffusionDistance + , uniforms.vTranslucencyColor + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + , translucencyColorMap + #endif + #endif + ); + + #ifdef SS_REFRACTION + surfaceAlbedo = subSurfaceOut.surfaceAlbedo; + #ifdef SS_LINKREFRACTIONTOTRANSPARENCY + alpha = subSurfaceOut.alpha; + #endif + #endif + #else + subSurfaceOut.specularEnvironmentReflectance = colorSpecularEnvironmentReflectance; + #endif + + // _____________________________ Direct Lighting Info __________________________________ + #include + + #include[0..maxSimultaneousLights] + + // _____________________________ Compute Final Lit Components ________________________ + #include +#endif // UNLIT + + #include + + #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/pbr2.vertex.fx b/packages/dev/core/src/ShadersWGSL/pbr2.vertex.fx new file mode 100644 index 00000000000..dd7d851f241 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/pbr2.vertex.fx @@ -0,0 +1,295 @@ +#define PBR_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_,ALBEDO,_VARYINGNAME_,Albedo) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) +#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient) +#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) +#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) +#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity) +#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler) +#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance) +#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance) +#include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy) +#endif + +#ifdef SUBSURFACE + #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness) + #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity) + #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor) +#endif + +// 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.baseDiffuseRoughness); + 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_,ALBEDO,_VARYINGNAME_,Albedo,_MATRIXNAME_,albedo,_INFONAME_,AlbedoInfos.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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) + #include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_MATRIXNAME_,ambient,_INFONAME_,AmbientInfos.x) + #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) + #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) + #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) + #include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_MATRIXNAME_,reflectivity,_INFONAME_,ReflectivityInfos.x) + #include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_MATRIXNAME_,microSurfaceSampler,_INFONAME_,MicroSurfaceSamplerInfos.x) + #include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_MATRIXNAME_,metallicReflectance,_INFONAME_,MetallicReflectanceInfos.x) + #include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_MATRIXNAME_,reflectance,_INFONAME_,ReflectanceInfos.x) + #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) + #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_MATRIXNAME_,clearCoat,_INFONAME_,ClearCoatInfos.x) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness,_MATRIXNAME_,clearCoatRoughness,_INFONAME_,ClearCoatInfos.z) + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_MATRIXNAME_,clearCoatBump,_INFONAME_,ClearCoatBumpInfos.x) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_MATRIXNAME_,clearCoatTint,_INFONAME_,ClearCoatTintInfos.x) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_MATRIXNAME_,iridescence,_INFONAME_,IridescenceInfos.x) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_MATRIXNAME_,iridescenceThickness,_INFONAME_,IridescenceInfos.z) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_MATRIXNAME_,sheen,_INFONAME_,SheenInfos.x) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness,_MATRIXNAME_,sheenRoughness,_INFONAME_,SheenInfos.z) + +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_MATRIXNAME_,anisotropy,_INFONAME_,AnisotropyInfos.x) +#endif + +#ifdef SUBSURFACE + #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness,_MATRIXNAME_,thickness,_INFONAME_,ThicknessInfos.x) + #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_MATRIXNAME_,refractionIntensity,_INFONAME_,RefractionIntensityInfos.x) + #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_MATRIXNAME_,translucencyIntensity,_INFONAME_,TranslucencyIntensityInfos.x) + #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_MATRIXNAME_,translucencyColor,_INFONAME_,TranslucencyColorInfos.x) +#endif + + // 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/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..ee338f27624 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -74,7 +75,7 @@ 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 PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..e2ef0b82009 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -70,7 +71,7 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } private async _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsAnisotropy, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..7d51a89c977 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,5 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -72,7 +73,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..4b98b0a6193 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -77,7 +78,7 @@ 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 PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..4061875421d 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -73,7 +74,7 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..c80e9794d50 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -70,7 +71,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { 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..480e8eb8df8 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -77,7 +78,7 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..bfb5304c3dd 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,5 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -72,7 +73,7 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts index 4f228ad3d07..2120598c1d0 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -74,7 +75,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax private _loadSpecularGlossinessPropertiesAsync(context: string, properties: IKHRMaterialsPbrSpecularGlossiness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..a99c04337a5 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,5 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -74,7 +75,7 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..e5c5d196148 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -83,7 +84,7 @@ 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..17674b2b99a 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -378,7 +379,7 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } const pbrMaterial = babylonMaterial; 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..c3dd1019330 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -68,7 +69,7 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..3929bb97f13 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,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -81,7 +82,7 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { // 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)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } 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..b3463735af8 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -47,7 +48,7 @@ export class MSFT_minecraftMesh implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { 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..f515f1954bf 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -47,7 +48,7 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${extraContext}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index b199e919678..dd3d399c8ec 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -17,6 +17,7 @@ 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { ITextureCreationOptions } from "core/Materials/Textures/texture"; import { Texture } from "core/Materials/Textures/texture"; @@ -2127,7 +2128,7 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } @@ -2227,7 +2228,12 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; - const babylonMaterial = new PBRMaterial(name, this._babylonScene); + let babylonMaterial; + if (this.parent.usePBR2) { + babylonMaterial = new PBRMaterial2(name, this._babylonScene); + } else { + babylonMaterial = new PBRMaterial(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; @@ -2295,7 +2301,7 @@ 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 PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } @@ -2360,7 +2366,7 @@ 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 PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { throw new Error(`${context}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/glTFFileLoader.ts b/packages/dev/loaders/src/glTF/glTFFileLoader.ts index 4da0f4a44c3..38f287c9d7b 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.usePBR2 = options.usePBR2 ?? this.usePBR2; 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 usePBR2 = false; + /** * Defines if the loader should create instances when multiple glTF nodes point to the same glTF mesh. Defaults to true. */ From 095b44cc3545fc72cb8c94d49907eee87b6a3038 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Thu, 19 Jun 2025 15:32:19 -0700 Subject: [PATCH 02/45] Try mixins for reusing defines in materials --- .../Background/backgroundMaterial.ts | 23 ++---------- .../core/src/Materials/Node/nodeMaterial.ts | 37 ++----------------- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 25 ++----------- .../core/src/Materials/PBR/pbrMaterial2.ts | 25 ++----------- .../imageProcessingConfiguration.defines.ts | 30 +++++++++++++++ .../core/src/Materials/standardMaterial.ts | 24 ++---------- .../dev/materials/src/water/waterMaterial.ts | 22 ++--------- 7 files changed, 54 insertions(+), 132 deletions(-) diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index 8caad63d4e0..cf82580c1c0 100644 --- a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts +++ b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts @@ -15,7 +15,7 @@ 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"; @@ -48,11 +48,13 @@ import { import { SerializationHelper } from "../../Misc/decorators.serialization"; import { ShaderLanguage } from "../shaderLanguage"; +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 +137,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; diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index f51b7058009..013d87906eb 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterial.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterial.ts @@ -67,7 +67,7 @@ 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"; @@ -91,8 +91,10 @@ export interface INodeMaterialEditorOptions { }; } +class NodeMaterialDefinesBase extends MaterialDefines {} + /** @internal */ -export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +export class NodeMaterialDefines extends ImageProcessingDefinesMixin(NodeMaterialDefinesBase) { /** Normal */ public NORMAL = false; /** Tangent */ @@ -177,37 +179,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 */ diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index 63fcb5abbaf..43133188e98 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -16,7 +16,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"; @@ -71,11 +71,13 @@ import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrende const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; +class PBRMaterialDefinesBase extends 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"; @@ -256,25 +258,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; diff --git a/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts b/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts index 39ef0957c06..4d29c78ff02 100644 --- a/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts +++ b/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts @@ -15,7 +15,7 @@ import { SerializationHelper } from "../../Misc/decorators.serialization"; import type { AbstractMesh } from "../../Meshes/abstractMesh"; import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; import { MaterialDefines } from "../../Materials/materialDefines"; -import type { IImageProcessingConfigurationDefines } from "../../Materials/imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines"; import { EffectFallbacks } from "../effectFallbacks"; import { AddClipPlaneUniforms } from "../clipPlaneMaterialHelper"; import { @@ -53,11 +53,13 @@ import type { SubMesh } from "../../Meshes/subMesh"; import { Logger } from "core/Misc/logger"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; + +class PBRMaterial2DefinesBase extends MaterialDefines {} /** * Manages the defines for the PBR Material. * @internal */ -export class PBRMaterial2Defines extends MaterialDefines implements IImageProcessingConfigurationDefines { +export class PBRMaterial2Defines extends ImageProcessingDefinesMixin(PBRMaterial2DefinesBase) { public PBR = true; public NUM_SAMPLES = "0"; @@ -238,25 +240,6 @@ export class PBRMaterial2Defines extends MaterialDefines implements IImageProces 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; 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/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 157a334484b..8668c879607 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -14,7 +14,7 @@ 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"; @@ -64,8 +64,10 @@ import { MaterialHelperGeometryRendering } from "./materialHelper.geometryrender const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; +class StandardMaterialDefinesBase extends MaterialDefines {} + /** @internal */ -export class StandardMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +export class StandardMaterialDefines extends ImageProcessingDefinesMixin(StandardMaterialDefinesBase) { public MAINUV1 = false; public MAINUV2 = false; public MAINUV3 = false; @@ -211,23 +213,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; @@ -243,7 +228,6 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr * @internal */ public IS_REFRACTION_LINEAR = false; - public EXPOSURE = false; public DECAL_AFTER_DETAIL = false; diff --git a/packages/dev/materials/src/water/waterMaterial.ts b/packages/dev/materials/src/water/waterMaterial.ts index cfc989f34e9..5e3cb408a6a 100644 --- a/packages/dev/materials/src/water/waterMaterial.ts +++ b/packages/dev/materials/src/water/waterMaterial.ts @@ -13,7 +13,7 @@ import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture"; import type { IEffectCreationOptions } from "core/Materials/effect"; import { MaterialDefines } from "core/Materials/materialDefines"; -import type { IImageProcessingConfigurationDefines } from "core/Materials/imageProcessingConfiguration.defines"; +import { ImageProcessingDefinesMixin } from "core/Materials/imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "core/Materials/imageProcessingConfiguration"; import { PushMaterial } from "core/Materials/pushMaterial"; import { MaterialFlags } from "core/Materials/materialFlags"; @@ -47,7 +47,9 @@ import { import "core/Rendering/boundingBoxRenderer"; -class WaterMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { +class WaterMaterialDefinesBase extends MaterialDefines {} + +class WaterMaterialDefines extends ImageProcessingDefinesMixin(WaterMaterialDefinesBase) { public BUMP = false; public REFLECTION = false; public CLIPPLANE = false; @@ -77,22 +79,6 @@ class WaterMaterialDefines extends MaterialDefines implements IImageProcessingCo public BUMPAFFECTSREFLECTION = false; public USE_WORLD_COORDINATES = false; - public IMAGEPROCESSING = false; - public VIGNETTE = false; - public VIGNETTEBLENDMODEMULTIPLY = false; - public VIGNETTEBLENDMODEOPAQUE = false; - public TONEMAPPING = 0; - public CONTRAST = false; - public EXPOSURE = 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; - constructor() { super(); this.rebuild(); From 7330638cc5c7cfd7838b945436cd55ed6a4596ba Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 20 Jun 2025 09:11:40 -0700 Subject: [PATCH 03/45] Move UV defines into a mixin --- .../core/src/Materials/Node/nodeMaterial.ts | 15 ++----------- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 15 ++----------- .../core/src/Materials/standardMaterial.ts | 15 ++----------- packages/dev/core/src/Materials/uv.defines.ts | 22 +++++++++++++++++++ .../dev/materials/src/water/waterMaterial.ts | 22 +++++++++++++++---- 5 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 packages/dev/core/src/Materials/uv.defines.ts diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index 013d87906eb..2e2c996b354 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterial.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterial.ts @@ -72,6 +72,7 @@ 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"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; @@ -91,7 +92,7 @@ export interface INodeMaterialEditorOptions { }; } -class NodeMaterialDefinesBase extends MaterialDefines {} +class NodeMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} /** @internal */ export class NodeMaterialDefines extends ImageProcessingDefinesMixin(NodeMaterialDefinesBase) { @@ -101,18 +102,6 @@ export class NodeMaterialDefines extends ImageProcessingDefinesMixin(NodeMateria 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; diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index 43133188e98..c3be535cf80 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -68,10 +68,11 @@ import { } from "../materialHelper.functions"; import { ShaderLanguage } from "../shaderLanguage"; import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering"; +import { UVDefinesMixin } from "../uv.defines"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; -class PBRMaterialDefinesBase extends MaterialDefines {} +class PBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} /** * Manages the defines for the PBR Material. @@ -83,18 +84,6 @@ export class PBRMaterialDefines extends ImageProcessingDefinesMixin(PBRMaterialD 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; diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 8668c879607..65030386c48 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -61,19 +61,14 @@ import { import { SerializationHelper } from "../Misc/decorators.serialization"; import { ShaderLanguage } from "./shaderLanguage"; import { MaterialHelperGeometryRendering } from "./materialHelper.geometryrendering"; +import { UVDefinesMixin } from "./uv.defines"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; -class StandardMaterialDefinesBase extends MaterialDefines {} +class StandardMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} /** @internal */ export class StandardMaterialDefines extends ImageProcessingDefinesMixin(StandardMaterialDefinesBase) { - public MAINUV1 = false; - public MAINUV2 = false; - public MAINUV3 = false; - public MAINUV4 = false; - public MAINUV5 = false; - public MAINUV6 = false; public DIFFUSE = false; public DIFFUSEDIRECTUV = 0; public BAKED_VERTEX_ANIMATION_TEXTURE = false; @@ -113,12 +108,6 @@ export class StandardMaterialDefines extends ImageProcessingDefinesMixin(Standar 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; 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/materials/src/water/waterMaterial.ts b/packages/dev/materials/src/water/waterMaterial.ts index 5e3cb408a6a..cfc989f34e9 100644 --- a/packages/dev/materials/src/water/waterMaterial.ts +++ b/packages/dev/materials/src/water/waterMaterial.ts @@ -13,7 +13,7 @@ import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture"; import type { IEffectCreationOptions } from "core/Materials/effect"; import { MaterialDefines } from "core/Materials/materialDefines"; -import { ImageProcessingDefinesMixin } from "core/Materials/imageProcessingConfiguration.defines"; +import type { IImageProcessingConfigurationDefines } from "core/Materials/imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "core/Materials/imageProcessingConfiguration"; import { PushMaterial } from "core/Materials/pushMaterial"; import { MaterialFlags } from "core/Materials/materialFlags"; @@ -47,9 +47,7 @@ import { import "core/Rendering/boundingBoxRenderer"; -class WaterMaterialDefinesBase extends MaterialDefines {} - -class WaterMaterialDefines extends ImageProcessingDefinesMixin(WaterMaterialDefinesBase) { +class WaterMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines { public BUMP = false; public REFLECTION = false; public CLIPPLANE = false; @@ -79,6 +77,22 @@ class WaterMaterialDefines extends ImageProcessingDefinesMixin(WaterMaterialDefi public BUMPAFFECTSREFLECTION = false; public USE_WORLD_COORDINATES = false; + public IMAGEPROCESSING = false; + public VIGNETTE = false; + public VIGNETTEBLENDMODEMULTIPLY = false; + public VIGNETTEBLENDMODEOPAQUE = false; + public TONEMAPPING = 0; + public CONTRAST = false; + public EXPOSURE = 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; + constructor() { super(); this.rebuild(); From c85e2223bd049d799a92a288dbde2c7295d505b9 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 20 Jun 2025 14:06:51 -0700 Subject: [PATCH 04/45] Add mixin for imageProcessing support in materials --- .../Background/backgroundMaterial.ts | 170 +---------- packages/dev/core/src/Materials/PBR/index.ts | 2 +- .../PBR/{pbrMaterial2.ts => pbr2Material.ts} | 264 +++++++----------- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 47 +--- .../dev/core/src/Materials/PBR/pbrMaterial.ts | 123 -------- .../dev/core/src/Materials/imageProcessing.ts | 193 +++++++++++++ .../core/src/Materials/standardMaterial.ts | 164 +---------- .../EXT_materials_diffuse_roughness.ts | 4 +- .../Extensions/KHR_materials_anisotropy.ts | 4 +- .../2.0/Extensions/KHR_materials_clearcoat.ts | 4 +- .../KHR_materials_diffuse_transmission.ts | 4 +- .../Extensions/KHR_materials_dispersion.ts | 4 +- .../KHR_materials_emissive_strength.ts | 4 +- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 4 +- .../Extensions/KHR_materials_iridescence.ts | 4 +- .../KHR_materials_pbrSpecularGlossiness.ts | 4 +- .../2.0/Extensions/KHR_materials_sheen.ts | 4 +- .../2.0/Extensions/KHR_materials_specular.ts | 4 +- .../Extensions/KHR_materials_transmission.ts | 4 +- .../2.0/Extensions/KHR_materials_unlit.ts | 4 +- .../2.0/Extensions/KHR_materials_volume.ts | 4 +- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 4 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 4 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 10 +- 24 files changed, 339 insertions(+), 698 deletions(-) rename packages/dev/core/src/Materials/PBR/{pbrMaterial2.ts => pbr2Material.ts} (89%) create mode 100644 packages/dev/core/src/Materials/imageProcessing.ts diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index cf82580c1c0..77ff895e8d0 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,7 +13,6 @@ 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 { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines"; import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; @@ -47,6 +45,7 @@ import { } from "../materialHelper.functions"; import { SerializationHelper } from "../../Misc/decorators.serialization"; import { ShaderLanguage } from "../shaderLanguage"; +import { ImageProcessingMixin } from "../imageProcessing"; class BackgroundMaterialDefinesBase extends MaterialDefines {} @@ -187,11 +186,12 @@ class BackgroundMaterialDefines extends ImageProcessingDefinesMixin(BackgroundMa } } +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. */ @@ -439,168 +439,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. diff --git a/packages/dev/core/src/Materials/PBR/index.ts b/packages/dev/core/src/Materials/PBR/index.ts index a04f9cd3f91..c97b2aa4adc 100644 --- a/packages/dev/core/src/Materials/PBR/index.ts +++ b/packages/dev/core/src/Materials/PBR/index.ts @@ -5,7 +5,7 @@ export * from "./pbrBRDFConfiguration"; export * from "./pbrClearCoatConfiguration"; export * from "./pbrIridescenceConfiguration"; export * from "./pbrMaterial"; -export * from "./pbrMaterial2"; +export * from "./pbr2Material"; export * from "./pbrMetallicRoughnessMaterial"; export * from "./pbrSpecularGlossinessMaterial"; export * from "./pbrSheenConfiguration"; diff --git a/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts b/packages/dev/core/src/Materials/PBR/pbr2Material.ts similarity index 89% rename from packages/dev/core/src/Materials/PBR/pbrMaterial2.ts rename to packages/dev/core/src/Materials/PBR/pbr2Material.ts index 4d29c78ff02..bffc22fa70a 100644 --- a/packages/dev/core/src/Materials/PBR/pbrMaterial2.ts +++ b/packages/dev/core/src/Materials/PBR/pbr2Material.ts @@ -3,9 +3,8 @@ import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture } fr import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import type { Scene } from "../../scene"; -import { Color3 } from "../../Maths/math.color"; -import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration"; -import type { ColorCurves } from "../../Materials/colorCurves"; +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"; @@ -14,8 +13,8 @@ import { SerializationHelper } from "../../Misc/decorators.serialization"; import type { AbstractMesh } from "../../Meshes/abstractMesh"; import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; -import { MaterialDefines } from "../../Materials/materialDefines"; -import { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines"; +import { MaterialDefines } from "../materialDefines"; +import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; import { EffectFallbacks } from "../effectFallbacks"; import { AddClipPlaneUniforms } from "../clipPlaneMaterialHelper"; import { @@ -48,35 +47,69 @@ import { PrePassConfiguration } from "../prePassConfiguration"; import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../../Materials/material"; import { ShaderLanguage } from "../shaderLanguage"; import { MaterialFlags } from "../materialFlags"; -import { Texture } from "../../Materials/Textures/texture"; +import { Texture } from "../Textures/texture"; import type { SubMesh } from "../../Meshes/subMesh"; import { Logger } from "core/Misc/logger"; +import { UVDefinesMixin } from "../uv.defines"; +import { Vector2, Vector3, Vector4 } from "core/Maths/math.vector"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; -class PBRMaterial2DefinesBase extends MaterialDefines {} +/** + * Defines a property for the PBR2Material. + */ +class Property { + /** + * Creates a new Property instance. + * @param name The name of the property in the shader + * @param defaultValue The default value of the property + * @param value The current value of the property, defaults to defaultValue + */ + constructor( + public name: string, + public defaultValue: T, + public value: T = defaultValue + ) {} + + /** + * Returns the number of components of the property based on its type. + */ + public get numComponents(): number { + if (typeof this.defaultValue === "number") { + return 1; // Single float + } 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 { + constructor( + public name: string, // Name in the shader + public value: Nullable = null // Texture value, default to null + ) {} +} + +class PBR2MaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} /** * Manages the defines for the PBR Material. * @internal */ -export class PBRMaterial2Defines extends ImageProcessingDefinesMixin(PBRMaterial2DefinesBase) { +export class PBR2MaterialDefines extends ImageProcessingDefinesMixin(PBR2MaterialDefinesBase) { 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; @@ -84,9 +117,7 @@ export class PBRMaterial2Defines extends ImageProcessingDefinesMixin(PBRMaterial public VERTEXCOLOR = false; public BASE_WEIGHT = false; - public BASE_WEIGHTDIRECTUV = 0; public BASE_DIFFUSE_ROUGHNESS = false; - public BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; public BAKED_VERTEX_ANIMATION_TEXTURE = false; @@ -288,6 +319,7 @@ export class PBRMaterial2Defines extends ImageProcessingDefinesMixin(PBRMaterial } } +// class PBR2MaterialBase extends ImageProcessingMixin(PBRBaseMaterial) {} /** * The Physically based material of BJS. * @@ -295,24 +327,24 @@ export class PBRMaterial2Defines extends ImageProcessingDefinesMixin(PBRMaterial * For more information, please refer to the documentation : * https://doc.babylonjs.com/features/featuresDeepDive/materials/using/introToPBR */ -export class PBRMaterial2 extends PBRBaseMaterial { +export class PBR2Material extends PBRBaseMaterial { /** - * PBRMaterial2TransparencyMode: No transparency mode, Alpha channel is not use. + * PBR2MaterialTransparencyMode: No transparency mode, Alpha channel is not use. */ public static override readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; /** - * PBRMaterial2TransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. + * PBR2MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. */ public static override readonly PBRMATERIAL_ALPHATEST = PBRBaseMaterial.PBRMATERIAL_ALPHATEST; /** - * PBRMaterial2TransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + * PBR2MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. */ public static override readonly PBRMATERIAL_ALPHABLEND = PBRBaseMaterial.PBRMATERIAL_ALPHABLEND; /** - * PBRMaterial2TransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + * PBR2MaterialTransparencyMode: 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 override readonly PBRMATERIAL_ALPHATESTANDBLEND = PBRBaseMaterial.PBRMATERIAL_ALPHATESTANDBLEND; @@ -323,6 +355,28 @@ export class PBRMaterial2 extends PBRBaseMaterial { */ public static override DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + /** + * Base Color uniform property. + */ + get baseColor(): Color3 { + return this._baseColor.value; + } + set baseColor(color: Color3) { + this._baseColor.value = color; + } + private _baseColor: Property = new Property("baseColor", Color3.White()); + + /** + * Base Color Texture property. + */ + get baseColorTexture(): Nullable { + return this._baseColorTexture.value; + } + set baseColorTexture(texture: Nullable) { + this._baseColorTexture.value = texture; + } + private _baseColorTexture: Sampler = new Sampler("baseColor"); + /** * Intensity of the direct lights e.g. the four lights available in your scene. * This impacts both the direct diffuse and specular highlights. @@ -404,7 +458,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientTextureImpactOnAnalyticalLights: number = PBRMaterial2.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + public ambientTextureImpactOnAnalyticalLights: number = PBR2Material.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; /** * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true. @@ -935,128 +989,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { 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 PBRMaterial2 instance. + * Instantiates a new PBR2Material instance. * * @param name The material name * @param scene The scene the material will be use in. @@ -1064,7 +997,6 @@ export class PBRMaterial2 extends PBRBaseMaterial { */ constructor(name: string, scene?: Scene, forceGLSL = false) { super(name, scene, forceGLSL); - this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene()); } @@ -1072,7 +1004,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { * @returns the name of this material class. */ public override getClassName(): string { - return "PBRMaterial2"; + return "gi"; } /** @@ -1082,8 +1014,8 @@ export class PBRMaterial2 extends PBRBaseMaterial { * @param rootUrl defines the root URL to use to load textures * @returns cloned material instance */ - public override clone(name: string, cloneTexturesOnlyOnce: boolean = true, rootUrl = ""): PBRMaterial2 { - const clone = SerializationHelper.Clone(() => new PBRMaterial2(name, this.getScene()), this, { cloneTexturesOnlyOnce }); + public override clone(name: string, cloneTexturesOnlyOnce: boolean = true, rootUrl = ""): PBR2Material { + const clone = SerializationHelper.Clone(() => new PBR2Material(name, this.getScene()), this, { cloneTexturesOnlyOnce }); clone.id = name; clone.name = name; @@ -1101,7 +1033,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { */ public override serialize(): any { const serializationObject = super.serialize(); - serializationObject.customType = "BABYLON.PBRMaterial2"; + serializationObject.customType = "BABYLON.PBR2Material"; return serializationObject; } @@ -1112,10 +1044,10 @@ export class PBRMaterial2 extends PBRBaseMaterial { * @param source - Serialized object. * @param scene - BJS scene instance. * @param rootUrl - url for the scene object - * @returns - PBRMaterial2 + * @returns - PBR2Material */ - public static override Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial2 { - const material = SerializationHelper.Parse(() => new PBRMaterial2(source.name, scene), source, scene, rootUrl); + public static override Parse(source: any, scene: Scene, rootUrl: string): PBR2Material { + const material = SerializationHelper.Parse(() => new PBR2Material(source.name, scene), source, scene, rootUrl); if (source.stencil) { material.stencil.parse(source.stencil, scene, rootUrl); @@ -1168,7 +1100,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { if (this._breakShaderLoadedCheck2) { return; } - const defines = new PBRMaterial2Defines(this._eventInfo.defineNames); + const defines = new PBR2MaterialDefines(this._eventInfo.defineNames); const effect = this._prepareEffect2(mesh, defines, undefined, undefined, localOptions.useInstances, localOptions.clipPlane, mesh.hasThinInstances)!; if (this._onEffectCreatedObservable) { onCreatedEffectParameters.effect = effect; @@ -1212,10 +1144,10 @@ export class PBRMaterial2 extends PBRBaseMaterial { if (!subMesh.materialDefines) { this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); - subMesh.materialDefines = new PBRMaterial2Defines(this._eventInfo.defineNames); + subMesh.materialDefines = new PBR2MaterialDefines(this._eventInfo.defineNames); } - const defines = subMesh.materialDefines; + const defines = subMesh.materialDefines; if (this._isReadyForSubMesh(subMesh)) { return true; } @@ -1359,7 +1291,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { if (!engine.getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) { mesh.createNormals(true); - Logger.Warn("PBRMaterial2: Normals have been created for the mesh: " + mesh.name); + Logger.Warn("PBR2Material: Normals have been created for the mesh: " + mesh.name); } const previousEffect = subMesh.effect; @@ -1408,7 +1340,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { private _prepareEffect2( mesh: AbstractMesh, - defines: PBRMaterial2Defines, + defines: PBR2MaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, useInstances: Nullable = null, @@ -1723,7 +1655,7 @@ export class PBRMaterial2 extends PBRBaseMaterial { private _prepareDefines2( mesh: AbstractMesh, - defines: PBRMaterial2Defines, + defines: PBR2MaterialDefines, useInstances: Nullable = null, useClipPlane: Nullable = null, useThinInstances: boolean = false @@ -1756,8 +1688,6 @@ export class PBRMaterial2 extends PBRBaseMaterial { } if (scene.texturesEnabled) { defines.ALBEDODIRECTUV = 0; - defines.BASE_WEIGHTDIRECTUV = 0; - defines.BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; defines.AMBIENTDIRECTUV = 0; defines.OPACITYDIRECTUV = 0; defines.EMISSIVEDIRECTUV = 0; @@ -2118,4 +2048,4 @@ export class PBRMaterial2 extends PBRBaseMaterial { private _breakShaderLoadedCheck2 = false; } -RegisterClass("BABYLON.PBRMaterial2", PBRMaterial2); +RegisterClass("BABYLON.PBR2Material", PBR2Material); diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index c3be535cf80..bca6b7f4e1d 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"; @@ -69,6 +68,7 @@ import { 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 }; @@ -296,6 +296,7 @@ export class PBRMaterialDefines extends ImageProcessingDefinesMixin(PBRMaterialD } } +class PBRBaseMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * The Physically based material base class of BJS. * @@ -305,7 +306,7 @@ export class PBRMaterialDefines extends ImageProcessingDefinesMixin(PBRMaterialD * @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. */ @@ -815,46 +816,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. */ 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..639d1061c9a --- /dev/null +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -0,0 +1,193 @@ +/* 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"; + +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/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 65030386c48..22b6cd44a42 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -62,6 +62,7 @@ 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 }; @@ -249,12 +250,13 @@ export class StandardMaterialDefines extends ImageProcessingDefinesMixin(Standar } } +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. @@ -601,64 +603,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; /** @@ -673,108 +617,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 */ 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 ee338f27624..2029a3aaf1f 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -75,7 +75,7 @@ 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 e2ef0b82009..2a89f37a970 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -71,7 +71,7 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } private async _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsAnisotropy, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 7d51a89c977..438c5e49dda 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,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -73,7 +73,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 4b98b0a6193..88185371315 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,7 +1,7 @@ /* eslint-disable github/no-then */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -78,7 +78,7 @@ 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 4061875421d..c4d12526646 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,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -74,7 +74,7 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 c80e9794d50..15b30b78e65 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -71,7 +71,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { 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 480e8eb8df8..b7aefce1d72 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -78,7 +78,7 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 bfb5304c3dd..1c9a62c37eb 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,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -73,7 +73,7 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts index 2120598c1d0..54081698e17 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts @@ -1,7 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -75,7 +75,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax private _loadSpecularGlossinessPropertiesAsync(context: string, properties: IKHRMaterialsPbrSpecularGlossiness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 a99c04337a5..c4d3aba8b9e 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,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -75,7 +75,7 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 e5c5d196148..25d7d3ccf8b 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -84,7 +84,7 @@ 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 17674b2b99a..a11e95c6f56 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -379,7 +379,7 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } const pbrMaterial = babylonMaterial; 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 c3dd1019330..15a0390af36 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,7 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -69,7 +69,7 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 3929bb97f13..513052f2896 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,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -82,7 +82,7 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } 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 b3463735af8..82a6559ba80 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -48,7 +48,7 @@ export class MSFT_minecraftMesh implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { 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 f515f1954bf..f45fc79ed69 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -48,7 +48,7 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${extraContext}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index dd3d399c8ec..f3a2fd646bd 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -17,7 +17,7 @@ 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 { PBRMaterial2 } from "core/Materials/PBR/pbrMaterial2"; +import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { ITextureCreationOptions } from "core/Materials/Textures/texture"; import { Texture } from "core/Materials/Textures/texture"; @@ -2128,7 +2128,7 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } @@ -2230,7 +2230,7 @@ export class GLTFLoader implements IGLTFLoader { this._babylonScene._blockEntityCollection = !!this._assetContainer; let babylonMaterial; if (this.parent.usePBR2) { - babylonMaterial = new PBRMaterial2(name, this._babylonScene); + babylonMaterial = new PBR2Material(name, this._babylonScene); } else { babylonMaterial = new PBRMaterial(name, this._babylonScene); } @@ -2301,7 +2301,7 @@ 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) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } @@ -2366,7 +2366,7 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBRMaterial2)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { throw new Error(`${context}: Material type not supported`); } From 6f0091093e5306d3a65a41b004e5a7492eb46507 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 20 Jun 2025 14:23:35 -0700 Subject: [PATCH 05/45] Fix compile warnings --- packages/dev/core/src/Materials/standardMaterial.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 22b6cd44a42..d2b46351eba 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"; @@ -16,7 +15,6 @@ import { PrePassConfiguration } from "./prePassConfiguration"; 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"; From 2bffe3ae046da406fd83d151d5ecd1e6751c3ab6 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 23 Jun 2025 10:50:18 -0700 Subject: [PATCH 06/45] Fix error with es6 build and imageProcessing mixin --- .../core/src/Materials/Node/nodeMaterial.ts | 64 +------------------ .../core/src/Materials/PBR/pbr2Material.ts | 2 +- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 24 +++---- .../dev/core/src/Materials/imageProcessing.ts | 8 ++- packages/dev/core/src/Materials/index.ts | 2 + .../core/src/Particles/baseParticleSystem.ts | 44 ++----------- 6 files changed, 28 insertions(+), 116 deletions(-) diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index 2e2c996b354..3c699c44048 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"; @@ -73,6 +71,7 @@ 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 }; @@ -232,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; @@ -376,30 +376,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 */ @@ -473,40 +449,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/pbr2Material.ts b/packages/dev/core/src/Materials/PBR/pbr2Material.ts index bffc22fa70a..6b37f716207 100644 --- a/packages/dev/core/src/Materials/PBR/pbr2Material.ts +++ b/packages/dev/core/src/Materials/PBR/pbr2Material.ts @@ -5,7 +5,7 @@ import type { Nullable } from "../../types"; import type { Scene } from "../../scene"; import { Color3, Color4 } from "../../Maths/math.color"; import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; -import type { BaseTexture } from "../../Materials/Textures/baseTexture"; +import type { BaseTexture } from "../Textures/baseTexture"; import { PBRBaseMaterial } from "./pbrBaseMaterial"; import { RegisterClass } from "../../Misc/typeStore"; import { Material } from "../material"; diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index bca6b7f4e1d..bffd6ec1e0e 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -15,25 +15,25 @@ import { PBRBRDFConfiguration } from "./pbrBRDFConfiguration"; import { PrePassConfiguration } from "../prePassConfiguration"; import { Color3, TmpColors } from "../../Maths/math.color"; -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"; -import { Material } from "../../Materials/material"; +import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; +import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; +import type { Effect, IEffectCreationOptions } from "../effect"; +import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../material"; +import { Material } from "../material"; import { MaterialPluginEvent } from "../materialPluginEvent"; -import { MaterialDefines } from "../../Materials/materialDefines"; -import { PushMaterial } from "../../Materials/pushMaterial"; +import { MaterialDefines } from "../materialDefines"; +import { PushMaterial } from "../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 type { BaseTexture } from "../Textures/baseTexture"; +import { Texture } from "../Textures/texture"; +import type { RenderTargetTexture } from "../Textures/renderTargetTexture"; +import type { CubeTexture } from "../Textures/cubeTexture"; import { MaterialFlags } from "../materialFlags"; import { Constants } from "../../Engines/constants"; import type { IAnimatable } from "../../Animations/animatable.interface"; -import "../../Materials/Textures/baseTexture.polynomial"; +import "../Textures/baseTexture.polynomial"; import { EffectFallbacks } from "../effectFallbacks"; import { PBRClearCoatConfiguration } from "./pbrClearCoatConfiguration"; diff --git a/packages/dev/core/src/Materials/imageProcessing.ts b/packages/dev/core/src/Materials/imageProcessing.ts index 639d1061c9a..7b9f29727f1 100644 --- a/packages/dev/core/src/Materials/imageProcessing.ts +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -3,8 +3,12 @@ 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"; +import type { BaseTexture } from "./Textures/baseTexture"; +import type { ColorCurves } from "./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; diff --git a/packages/dev/core/src/Materials/index.ts b/packages/dev/core/src/Materials/index.ts index 3b2e6566225..fa8f77ae048 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"; @@ -40,6 +41,7 @@ export * from "./GaussianSplatting/gaussianSplattingMaterial"; export * from "./materialHelper.functions"; export * from "./materialHelper.geometryrendering"; export * from "./materialStencilState"; +export * from "./uv.defines"; import "./material.decalMap"; // async-loaded shaders 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; } From 735bee9a9b12630b2b0c6c764c0afcb05f7c97c6 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 24 Jun 2025 10:50:09 -0700 Subject: [PATCH 07/45] Separating reflection (IBL) defines and uniforms --- .../Background/backgroundMaterial.ts | 102 +----- .../core/src/Materials/PBR/pbr2Material.ts | 163 +-------- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 289 +-------------- .../src/Materials/materialHelper.functions.ts | 341 +++++++++++++++++- .../core/src/Materials/standardMaterial.ts | 106 +----- .../backgroundUboDeclaration.fx | 7 +- .../ShadersInclude/defaultUboDeclaration.fx | 9 +- .../ShadersInclude/pbrUboDeclaration.fx | 17 +- .../backgroundUboDeclaration.fx | 11 +- .../ShadersInclude/defaultUboDeclaration.fx | 8 +- .../ShadersInclude/pbrUboDeclaration.fx | 17 +- 11 files changed, 431 insertions(+), 639 deletions(-) diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index 77ff895e8d0..e8c272d634d 100644 --- a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts +++ b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts @@ -16,7 +16,6 @@ import { PushMaterial } from "../../Materials/pushMaterial"; 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"; @@ -32,16 +31,21 @@ 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"; @@ -597,57 +601,14 @@ export class BackgroundMaterial extends BackgroundMaterialBase { } 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; @@ -662,25 +623,9 @@ export class BackgroundMaterial extends BackgroundMaterialBase { 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; } } @@ -779,9 +724,6 @@ export class BackgroundMaterial extends BackgroundMaterialBase { "vPrimaryColor", "vPrimaryColorShadow", - "vReflectionInfos", - "reflectionMatrix", - "vReflectionMicrosurfaceInfos", "fFovMultiplier", "shadowLevel", @@ -798,7 +740,8 @@ export class BackgroundMaterial extends BackgroundMaterialBase { ]; AddClipPlaneUniforms(uniforms); - const samplers = ["diffuseSampler", "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh"]; + const samplers = ["diffuseSampler"]; + PrepareUniformsAndSamplersForIBL(uniforms, samplers, false); const uniformBuffers = ["Material", "Scene"]; if (ImageProcessingConfiguration) { @@ -908,10 +851,7 @@ export class BackgroundMaterial extends BackgroundMaterialBase { 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); @@ -920,6 +860,8 @@ export class BackgroundMaterial extends BackgroundMaterialBase { this._uniformBuffer.addUniform("vReflectionControl", 4); this._uniformBuffer.addUniform("projectedGroundInfos", 2); + PrepareUniformLayoutForIBL(this._uniformBuffer, true, false, false); + this._uniformBuffer.create(); } @@ -987,17 +929,7 @@ export class BackgroundMaterial extends BackgroundMaterialBase { 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); } if (this.shadowLevel > 0) { @@ -1027,15 +959,7 @@ export class BackgroundMaterial extends BackgroundMaterialBase { } 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/PBR/pbr2Material.ts b/packages/dev/core/src/Materials/PBR/pbr2Material.ts index 6b37f716207..e16fe3d2dcf 100644 --- a/packages/dev/core/src/Materials/PBR/pbr2Material.ts +++ b/packages/dev/core/src/Materials/PBR/pbr2Material.ts @@ -32,12 +32,14 @@ import { PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, + PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, PrepareUniformsAndSamplersList, + PrepareUniformsAndSamplersForIBL, } from "../materialHelper.functions"; import { Constants } from "../../Engines/constants"; import { VertexBuffer } from "../../Buffers/buffer"; @@ -47,7 +49,6 @@ import { PrePassConfiguration } from "../prePassConfiguration"; import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../../Materials/material"; import { ShaderLanguage } from "../shaderLanguage"; import { MaterialFlags } from "../materialFlags"; -import { Texture } from "../Textures/texture"; import type { SubMesh } from "../../Meshes/subMesh"; import { Logger } from "core/Misc/logger"; import { UVDefinesMixin } from "../uv.defines"; @@ -1483,7 +1484,6 @@ export class PBR2Material extends PBRBaseMaterial { "vMetallicReflectanceFactors", "vEmissiveColor", "visibility", - "vReflectionColor", "vFogInfos", "vFogColor", "pointSize", @@ -1492,12 +1492,8 @@ export class PBR2Material extends PBRBaseMaterial { "vBaseDiffuseRoughnessInfos", "vAmbientInfos", "vOpacityInfos", - "vReflectionInfos", - "vReflectionPosition", - "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", - "vReflectionFilteringInfo", "vMetallicReflectanceInfos", "vReflectanceInfos", "vMicroSurfaceSamplerInfos", @@ -1509,7 +1505,6 @@ export class PBR2Material extends PBRBaseMaterial { "baseDiffuseRoughnessMatrix", "ambientMatrix", "opacityMatrix", - "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", @@ -1520,26 +1515,6 @@ export class PBR2Material extends PBRBaseMaterial { "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", @@ -1558,10 +1533,6 @@ export class PBR2Material extends PBRBaseMaterial { "bumpSampler", "lightmapSampler", "opacitySampler", - "reflectionSampler", - "reflectionSamplerLow", - "reflectionSamplerHigh", - "irradianceSampler", "microSurfaceSampler", "environmentBrdfSampler", "boneSampler", @@ -1570,11 +1541,12 @@ export class PBR2Material extends PBRBaseMaterial { "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 }; @@ -1736,126 +1708,13 @@ export class PBR2Material extends PBRBaseMaterial { } const reflectionTexture = this._getReflectionTexture2(); - 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"); diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index bffd6ec1e0e..bb1f8131403 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -25,9 +25,7 @@ import { MaterialDefines } from "../materialDefines"; import { PushMaterial } from "../pushMaterial"; import type { BaseTexture } from "../Textures/baseTexture"; -import { Texture } from "../Textures/texture"; import type { RenderTargetTexture } from "../Textures/renderTargetTexture"; -import type { CubeTexture } from "../Textures/cubeTexture"; import { MaterialFlags } from "../materialFlags"; import { Constants } from "../../Engines/constants"; @@ -50,6 +48,8 @@ import { BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, + BindIBLParameters, + BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, @@ -58,12 +58,15 @@ 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"; @@ -1408,7 +1411,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "vMetallicReflectanceFactors", "vEmissiveColor", "visibility", - "vReflectionColor", "vFogInfos", "vFogColor", "pointSize", @@ -1417,12 +1419,8 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "vBaseDiffuseRoughnessInfos", "vAmbientInfos", "vOpacityInfos", - "vReflectionInfos", - "vReflectionPosition", - "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", - "vReflectionFilteringInfo", "vMetallicReflectanceInfos", "vReflectanceInfos", "vMicroSurfaceSamplerInfos", @@ -1434,7 +1432,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "baseDiffuseRoughnessMatrix", "ambientMatrix", "opacityMatrix", - "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", @@ -1445,26 +1442,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "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", @@ -1483,10 +1460,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "bumpSampler", "lightmapSampler", "opacitySampler", - "reflectionSampler", - "reflectionSamplerLow", - "reflectionSamplerHigh", - "irradianceSampler", "microSurfaceSampler", "environmentBrdfSampler", "boneSampler", @@ -1495,11 +1468,12 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { "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 }; @@ -1665,126 +1639,13 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { } 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"); @@ -2023,10 +1884,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { 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); @@ -2039,16 +1896,11 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { 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); @@ -2062,28 +1914,8 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { 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); super.buildUniformLayout(); } @@ -2183,73 +2015,6 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { 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"); @@ -2297,6 +2062,8 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { } } + BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, this._reflectionColor); + // Point size if (this.pointsCloud) { ubo.updateFloat("pointSize", this.pointSize); @@ -2321,7 +2088,7 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { } 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 { @@ -2369,25 +2136,7 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { 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/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index 976429e345f..829693b1330 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -17,8 +17,11 @@ 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 type { IColor3Like } from "core/Maths"; +import { MaterialFlags } from "./materialFlags"; +import { Texture } from "./Textures/texture"; +import type { CubeTexture } from "./Textures/cubeTexture"; // Temps const TempFogColor: IColor3Like = { r: 0, g: 0, b: 0 }; @@ -266,6 +269,109 @@ 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 reflectionColor The color to use for the reflection + */ +export function BindIBLParameters( + scene: Scene, + defines: any, + ubo: UniformBuffer, + reflectionTexture: Nullable = null, + realTimeFiltering: 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 ((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 (!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); + } + } + 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. @@ -612,6 +718,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 @@ -1136,6 +1375,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 @@ -1188,3 +1472,58 @@ 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 useAdvanced Add advanced uniforms for IBL if true + * @param supportSH Add uniforms for spherical harmonics if true + */ +export function PrepareUniformLayoutForIBL( + ubo: UniformBuffer, + supportTextureInfo: boolean = false, + supportLocalProjection: boolean = false, + useAdvanced: boolean = false, + supportSH: 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 (useAdvanced) { + ubo.addUniform("vReflectionFilteringInfo", 2); + ubo.addUniform("vReflectionColor", 3); + ubo.addUniform("vReflectionDominantDirection", 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 d2b46351eba..5aa4f555225 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -23,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"; @@ -41,6 +40,7 @@ import { BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, + BindIBLParameters, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, @@ -49,12 +49,15 @@ 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"; @@ -227,25 +230,6 @@ export class StandardMaterialDefines extends ImageProcessingDefinesMixin(Standar 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) {} @@ -843,60 +827,9 @@ export class StandardMaterial extends StandardMaterialBase { } 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()) { @@ -1204,7 +1137,6 @@ export class StandardMaterial extends StandardMaterialBase { "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", - "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", @@ -1214,7 +1146,6 @@ export class StandardMaterial extends StandardMaterialBase { "diffuseMatrix", "ambientMatrix", "opacityMatrix", - "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", @@ -1230,8 +1161,6 @@ export class StandardMaterial extends StandardMaterialBase { "emissiveRightColor", "refractionLeftColor", "refractionRightColor", - "vReflectionPosition", - "vReflectionSize", "vRefractionPosition", "vRefractionSize", "logarithmicDepthConstant", @@ -1263,6 +1192,7 @@ export class StandardMaterial extends StandardMaterialBase { "areaLightsLTC2Sampler", ]; + PrepareUniformsAndSamplersForIBL(uniforms, samplers, false); const uniformBuffers = ["Material", "Scene", "Mesh"]; const indexParameters = { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }; @@ -1399,9 +1329,6 @@ export class StandardMaterial extends StandardMaterialBase { 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); @@ -1410,7 +1337,6 @@ export class StandardMaterial extends StandardMaterialBase { 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); @@ -1428,6 +1354,8 @@ export class StandardMaterial extends StandardMaterialBase { ubo.addUniform("vAmbientColor", 3); ubo.addUniform("cameraInfo", 4); + PrepareUniformLayoutForIBL(ubo, false, true); + super.buildUniformLayout(); } @@ -1542,19 +1470,7 @@ export class StandardMaterial extends StandardMaterialBase { 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); if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); 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/pbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx index 47a2252ac9d..5842558c3ce 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; @@ -69,6 +61,15 @@ uniform Material { vec2 vReflectanceInfos; mat4 reflectanceMatrix; + vec2 vReflectionInfos; + mat4 reflectionMatrix; + vec3 vReflectionMicrosurfaceInfos; + vec3 vReflectionPosition; + vec3 vReflectionSize; + vec2 vReflectionFilteringInfo; + vec3 vReflectionColor; + vec3 vReflectionDominantDirection; + vec3 vSphericalL00; vec3 vSphericalL1_1; vec3 vSphericalL10; 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/pbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx index e0922402feb..f5aeed5f908 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; @@ -44,6 +36,15 @@ uniform metallicReflectanceMatrix: mat4x4f; uniform vReflectanceInfos: vec2f; uniform reflectanceMatrix: mat4x4f; +uniform vReflectionInfos: vec2f; +uniform reflectionMatrix: mat4x4f; +uniform vReflectionMicrosurfaceInfos: vec3f; +uniform vReflectionPosition: vec3f; +uniform vReflectionSize: vec3f; +uniform vReflectionFilteringInfo: vec2f; +uniform vReflectionColor: vec3f; +uniform vReflectionDominantDirection: vec3f; + uniform vSphericalL00: vec3f; uniform vSphericalL1_1: vec3f; uniform vSphericalL10: vec3f; From 3d81ea5351f472c1c2c5316fc162794249c027be Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 24 Jun 2025 15:14:03 -0700 Subject: [PATCH 08/45] Remove pbrBaseMaterial as base class for PBR2 --- .../Background/backgroundMaterial.ts | 2 +- .../core/src/Materials/PBR/pbr2Material.ts | 1865 ++++++++++++++--- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 4 +- .../src/Materials/materialHelper.functions.ts | 39 +- .../core/src/Materials/standardMaterial.ts | 2 +- .../ShadersInclude/pbrUboDeclaration.fx | 2 +- .../ShadersInclude/pbrUboDeclaration.fx | 2 +- .../EXT_materials_diffuse_roughness.ts | 4 +- .../Extensions/KHR_materials_anisotropy.ts | 3 +- .../2.0/Extensions/KHR_materials_clearcoat.ts | 3 +- .../KHR_materials_diffuse_transmission.ts | 3 +- .../Extensions/KHR_materials_dispersion.ts | 3 +- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 3 +- .../Extensions/KHR_materials_iridescence.ts | 3 +- .../2.0/Extensions/KHR_materials_sheen.ts | 3 +- .../Extensions/KHR_materials_transmission.ts | 3 +- .../2.0/Extensions/KHR_materials_volume.ts | 3 +- 17 files changed, 1570 insertions(+), 377 deletions(-) diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index e8c272d634d..540ea120722 100644 --- a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts +++ b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts @@ -929,7 +929,7 @@ export class BackgroundMaterial extends BackgroundMaterialBase { BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse"); } - BindIBLParameters(scene, defines, this._uniformBuffer, reflectionTexture); + BindIBLParameters(scene, defines, this._uniformBuffer, reflectionTexture, false, true); } if (this.shadowLevel > 0) { diff --git a/packages/dev/core/src/Materials/PBR/pbr2Material.ts b/packages/dev/core/src/Materials/PBR/pbr2Material.ts index e16fe3d2dcf..1d08c1d3969 100644 --- a/packages/dev/core/src/Materials/PBR/pbr2Material.ts +++ b/packages/dev/core/src/Materials/PBR/pbr2Material.ts @@ -2,8 +2,8 @@ import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture } from "../../Misc/decorators"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; -import type { Scene } from "../../scene"; -import { Color3, Color4 } from "../../Maths/math.color"; +import { Scene } from "../../scene"; +import { Color3, Color4, TmpColors } from "../../Maths/math.color"; import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; import type { BaseTexture } from "../Textures/baseTexture"; import { PBRBaseMaterial } from "./pbrBaseMaterial"; @@ -16,14 +16,16 @@ import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; import { MaterialDefines } from "../materialDefines"; import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; import { EffectFallbacks } from "../effectFallbacks"; -import { AddClipPlaneUniforms } from "../clipPlaneMaterialHelper"; +import { AddClipPlaneUniforms, BindClipPlane } from "../clipPlaneMaterialHelper"; import { - // BindBonesParameters, - // BindFogParameters, - // BindLights, - // BindLogDepth, - // BindMorphTargetParameters, - // BindTextureMatrix, + BindBonesParameters, + BindFogParameters, + BindLights, + BindLogDepth, + BindMorphTargetParameters, + BindTextureMatrix, + BindIBLParameters, + BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, @@ -40,6 +42,7 @@ import { PrepareDefinesForPrePass, PrepareUniformsAndSamplersList, PrepareUniformsAndSamplersForIBL, + PrepareUniformLayoutForIBL, } from "../materialHelper.functions"; import { Constants } from "../../Engines/constants"; import { VertexBuffer } from "../../Buffers/buffer"; @@ -53,6 +56,13 @@ import type { SubMesh } from "../../Meshes/subMesh"; import { Logger } from "core/Misc/logger"; import { UVDefinesMixin } from "../uv.defines"; import { Vector2, Vector3, Vector4 } 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 }; @@ -320,6 +330,7 @@ export class PBR2MaterialDefines extends ImageProcessingDefinesMixin(PBR2Materia } } +class PBR2BaseMaterial extends ImageProcessingMixin(PushMaterial) {} // class PBR2MaterialBase extends ImageProcessingMixin(PBRBaseMaterial) {} /** * The Physically based material of BJS. @@ -328,33 +339,33 @@ export class PBR2MaterialDefines extends ImageProcessingDefinesMixin(PBR2Materia * For more information, please refer to the documentation : * https://doc.babylonjs.com/features/featuresDeepDive/materials/using/introToPBR */ -export class PBR2Material extends PBRBaseMaterial { +export class PBR2Material extends PBR2BaseMaterial { /** * PBR2MaterialTransparencyMode: No transparency mode, Alpha channel is not use. */ - public static override readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; + public static readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; /** * PBR2MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. */ - public static override readonly PBRMATERIAL_ALPHATEST = PBRBaseMaterial.PBRMATERIAL_ALPHATEST; + public static readonly PBRMATERIAL_ALPHATEST = PBRBaseMaterial.PBRMATERIAL_ALPHATEST; /** * PBR2MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. */ - public static override readonly PBRMATERIAL_ALPHABLEND = PBRBaseMaterial.PBRMATERIAL_ALPHABLEND; + public static readonly PBRMATERIAL_ALPHABLEND = PBRBaseMaterial.PBRMATERIAL_ALPHABLEND; /** * PBR2MaterialTransparencyMode: 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 override readonly PBRMATERIAL_ALPHATESTANDBLEND = PBRBaseMaterial.PBRMATERIAL_ALPHATESTANDBLEND; + 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 override DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + public static DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; /** * Base Color uniform property. @@ -587,21 +598,6 @@ export class PBR2Material extends PBRBaseMaterial { @expandToProperty("_markAllSubMeshesAsTexturesDirty", null) public lightmapTexture: Nullable; - /** - * Stores the refracted light information in a texture. - */ - public get refractionTexture(): Nullable { - return this.subSurface.refractionTexture; - } - public set refractionTexture(value: Nullable) { - this.subSurface.refractionTexture = value; - if (value) { - this.subSurface.isRefractionEnabled = true; - } else if (!this.subSurface.linkRefractionWithTransparency) { - this.subSurface.isRefractionEnabled = false; - } - } - /** * The color of a material in ambient lighting. */ @@ -658,45 +654,6 @@ export class PBR2Material extends PBRBaseMaterial { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public microSurface = 1.0; - /** - * Index of refraction of the material base layer. - * https://en.wikipedia.org/wiki/List_of_refractive_indices - * - * This does not only impact refraction but also the Base F0 of Dielectric Materials. - * - * From dielectric fresnel rules: F0 = square((iorT - iorI) / (iorT + iorI)) - */ - public get indexOfRefraction(): number { - return this.subSurface.indexOfRefraction; - } - public set indexOfRefraction(value: number) { - this.subSurface.indexOfRefraction = value; - } - - /** - * Controls if refraction needs to be inverted on Y. This could be useful for procedural texture. - */ - public get invertRefractionY(): boolean { - return this.subSurface.invertRefractionY; - } - public set invertRefractionY(value: boolean) { - this.subSurface.invertRefractionY = value; - } - - /** - * This parameters will make the material used its opacity to control how much it is refracting against not. - * Materials half opaque for instance using refraction could benefit from this control. - */ - public get linkRefractionWithTransparency(): boolean { - return this.subSurface.linkRefractionWithTransparency; - } - public set linkRefractionWithTransparency(value: boolean) { - this.subSurface.linkRefractionWithTransparency = value; - if (value) { - this.subSurface.isRefractionEnabled = true; - } - } - /** * If true, the light map contains occlusion information instead of lighting info. */ @@ -990,356 +947,1580 @@ export class PBR2Material extends PBRBaseMaterial { public applyDecalMapAfterDetailMap = false; /** - * Instantiates a new PBR2Material 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 + * PBRMaterialLightFalloff Physical: light is falling off following the inverse squared distance law. */ - constructor(name: string, scene?: Scene, forceGLSL = false) { - super(name, scene, forceGLSL); - this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene()); - } + public static readonly LIGHTFALLOFF_PHYSICAL = 0; /** - * @returns the name of this material class. + * PBRMaterialLightFalloff gltf: light is falling off as described in the gltf moving to PBR document + * to enhance interoperability with other engines. */ - public override getClassName(): string { - return "gi"; - } + public static readonly LIGHTFALLOFF_GLTF = 1; /** - * 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 diffuse 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 + * PBRMaterialLightFalloff Standard: light is falling off like in the standard material + * to enhance interoperability with other materials. */ - public override clone(name: string, cloneTexturesOnlyOnce: boolean = true, rootUrl = ""): PBR2Material { - const clone = SerializationHelper.Clone(() => new PBR2Material(name, this.getScene()), this, { cloneTexturesOnlyOnce }); + public static readonly LIGHTFALLOFF_STANDARD = 2; - clone.id = name; - clone.name = name; + /** + * 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; - this.stencil.copyTo(clone.stencil); + /** + * 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; - this._clonePlugins(clone, rootUrl); + /** + * 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; - return clone; - } + /** + * 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; /** - * Serializes this PBR Material. - * @returns - An object with the serialized material. + * This is a special control allowing the reduction of the specular highlights coming from the + * four lights of the scene. Those highlights may not be needed in full environment lighting. + * @internal */ - public override serialize(): any { - const serializationObject = super.serialize(); - serializationObject.customType = "BABYLON.PBR2Material"; + public _specularIntensity: number = 1.0; - return serializationObject; - } + /** + * This stores the direct, emissive, environment, and specular light intensities into a Vector4. + */ + private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, this._specularIntensity); - // 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 - PBR2Material + * Debug Control allowing disabling the bump map on this material. + * @internal */ - public static override Parse(source: any, scene: Scene, rootUrl: string): PBR2Material { - const material = SerializationHelper.Parse(() => new PBR2Material(source.name, scene), source, scene, rootUrl); + public _disableBumpMap: boolean = false; - if (source.stencil) { - material.stencil.parse(source.stencil, scene, rootUrl); - } + /** + * AKA Diffuse Texture in standard nomenclature. + * @internal + */ + public _albedoTexture: Nullable = null; - Material._ParsePlugins(source, material, scene, rootUrl); + /** + * Base Weight texture (multiplier to the diffuse and metal lobes). + * @internal + */ + public _baseWeightTexture: Nullable = null; - // The code block below ensures backward compatibility with serialized materials before plugins are automatically serialized. - if (source.clearCoat) { - material.clearCoat.parse(source.clearCoat, scene, rootUrl); - } - if (source.anisotropy) { - material.anisotropy.parse(source.anisotropy, scene, rootUrl); - } - if (source.brdf) { - material.brdf.parse(source.brdf, scene, rootUrl); - } - if (source.sheen) { - material.sheen.parse(source.sheen, scene, rootUrl); - } - if (source.subSurface) { - material.subSurface.parse(source.subSurface, scene, rootUrl); - } - if (source.iridescence) { - material.iridescence.parse(source.iridescence, scene, rootUrl); - } + /** + * Base Diffuse Roughness texture (roughness of the diffuse lobe). + * @internal + */ + public _baseDiffuseRoughnessTexture: Nullable = null; - return material; - } + /** + * AKA Occlusion Texture in other nomenclature. + * @internal + */ + public _ambientTexture: Nullable = null; /** - * 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 + * AKA Occlusion Texture Intensity in other nomenclature. + * @internal */ - public override forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial): void { - const localOptions = { - clipPlane: false, - useInstances: false, - ...options, - }; + public _ambientTextureStrength: number = 1.0; - if (!this._uniformBufferLayoutBuilt) { - this.buildUniformLayout(); - } + /** + * Defines how much the AO map is occluding the analytical lights (point spot...). + * 1 means it completely occludes it + * 0 mean it has no impact + * @internal + */ + public _ambientTextureImpactOnAnalyticalLights: number = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; - this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); - const checkReady = () => { - if (this._breakShaderLoadedCheck2) { - return; - } - const defines = new PBR2MaterialDefines(this._eventInfo.defineNames); - const effect = this._prepareEffect2(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(); - } + /** + * Stores the alpha values in a texture. + * @internal + */ + public _opacityTexture: Nullable = null; /** - * 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. + * Stores the reflection values in a texture. + * @internal */ - public override isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean { - if (!this._uniformBufferLayoutBuilt) { - this.buildUniformLayout(); - } + public _reflectionTexture: Nullable = null; - const drawWrapper = subMesh._drawWrapper; + /** + * Stores the emissive values in a texture. + * @internal + */ + public _emissiveTexture: Nullable = null; - if (drawWrapper.effect && this.isFrozen) { - if (drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) { - return true; - } - } + /** + * AKA Specular texture in other nomenclature. + * @internal + */ + public _reflectivityTexture: Nullable = null; - if (!subMesh.materialDefines) { - this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); - subMesh.materialDefines = new PBR2MaterialDefines(this._eventInfo.defineNames); - } + /** + * Used to switch from specular/glossiness to metallic/roughness workflow. + * @internal + */ + public _metallicTexture: Nullable = null; - const defines = subMesh.materialDefines; - if (this._isReadyForSubMesh(subMesh)) { - return true; - } + /** + * Specifies the metallic scalar of the metallic/roughness workflow. + * Can also be used to scale the metalness values of the metallic texture. + * @internal + */ + public _metallic: Nullable = null; - const scene = this.getScene(); - const engine = scene.getEngine(); + /** + * Specifies the roughness scalar of the metallic/roughness workflow. + * Can also be used to scale the roughness values of the metallic texture. + * @internal + */ + public _roughness: Nullable = null; - if (defines._areTexturesDirty) { - this._eventInfo.hasRenderTargetTextures = false; - this._callbackPluginEventHasRenderTargetTextures(this._eventInfo); - this._cacheHasRenderTargetTextures = this._eventInfo.hasRenderTargetTextures; - if (scene.texturesEnabled) { - if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { - if (!this._albedoTexture.isReadyOrNotBlocking()) { - return false; - } - } + /** + * In metallic workflow, specifies an F0 factor to help configuring the material F0. + * By default the indexOfrefraction is used to compute F0; + * + * This is used as a factor against the default reflectance at normal incidence to tweak it. + * + * F0 = defaultF0 * metallicF0Factor * metallicReflectanceColor; + * F90 = metallicReflectanceColor; + * @internal + */ + public _metallicF0Factor = 1; - if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { - if (!this._baseWeightTexture.isReadyOrNotBlocking()) { - return false; - } + /** + * In metallic workflow, specifies an F0 color. + * By default the F90 is always 1; + * + * Please note that this factor is also used as a factor against the default reflectance at normal incidence. + * + * F0 = defaultF0_from_IOR * metallicF0Factor * metallicReflectanceColor + * F90 = metallicF0Factor; + * @internal + */ + public _metallicReflectanceColor = Color3.White(); + + /** + * Specifies that only the A channel from _metallicReflectanceTexture should be used. + * If false, both RGB and A channels will be used + * @internal + */ + public _useOnlyMetallicFromMetallicReflectanceTexture = false; + + /** + * Defines to store metallicReflectanceColor in RGB and metallicF0Factor in A + * This is multiply against the scalar values defined in the material. + * @internal + */ + public _metallicReflectanceTexture: Nullable = null; + + /** + * Defines to store reflectanceColor in RGB + * This is multiplied against the scalar values defined in the material. + * If both _reflectanceTexture and _metallicReflectanceTexture textures are provided and _useOnlyMetallicFromMetallicReflectanceTexture + * is false, _metallicReflectanceTexture takes precedence and _reflectanceTexture is not used + * @internal + */ + public _reflectanceTexture: Nullable = null; + + /** + * Used to enable roughness/glossiness fetch from a separate channel depending on the current mode. + * Gray Scale represents roughness in metallic mode and glossiness in specular mode. + * @internal + */ + public _microSurfaceTexture: Nullable = null; + + /** + * 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 Diffuse Color in other nomenclature. + * @internal + */ + public _albedoColor = new Color3(1, 1, 1); + + /** + * Base Weight (multiplier to the diffuse and metal lobes). + * @internal + */ + public _baseWeight = 1; + + /** + * Base Diffuse Roughness (roughness of the diffuse lobe). + * Can also be used to scale the corresponding texture. + * @internal + */ + public _baseDiffuseRoughness: Nullable = null; + + /** + * 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); + + /** + * The color applied when light is emitted from a material. + * @internal + */ + public _emissiveColor = new Color3(0, 0, 0); + + /** + * AKA Glossiness in other nomenclature. + * @internal + */ + public _microSurface = 0.9; + + /** + * 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 roughness information in its alpha channel. + * @internal + */ + public _useRoughnessFromMetallicTextureAlpha = true; + + /** + * Specifies if the metallic texture contains the roughness information in its green channel. + * @internal + */ + public _useRoughnessFromMetallicTextureGreen = false; + + /** + * Specifies if the metallic texture contains the metallness information in its blue channel. + * @internal + */ + public _useMetallnessFromMetallicTextureBlue = 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); + + /** + * Sets the global ambient color for the material used in lighting calculations. + */ + private _globalAmbientColor = new Color3(0, 0, 0); + + /** + * 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 PBR2Material 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()); + } + + /** + * 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 "PBR2Material"; + } + + /** + * 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.alpha < 1.0 || this._opacityTexture != 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._albedoTexture != null && this._albedoTexture.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._albedoTexture != null && this._albedoTexture.hasAlpha) || this._opacityTexture != null; + } + + /** + * @returns the texture used for the alpha test. + */ + public override getAlphaTestTexture(): Nullable { + return this._albedoTexture; + } + + /** + * 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 diffuse 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 = ""): PBR2Material { + const clone = SerializationHelper.Clone(() => new PBR2Material(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.PBR2Material"; + + 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 - PBR2Material + */ + public static override Parse(source: any, scene: Scene, rootUrl: string): PBR2Material { + const material = SerializationHelper.Parse(() => new PBR2Material(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 PBR2MaterialDefines(this._eventInfo.defineNames); + 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 PBR2MaterialDefines(this._eventInfo.defineNames); + } + + 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) { + if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + if (!this._albedoTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { + if (!this._baseWeightTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { + if (!this._baseDiffuseRoughnessTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { + if (!this._ambientTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { + if (!this._opacityTexture.isReadyOrNotBlocking()) { + return false; + } + } + + const reflectionTexture = this._getReflectionTexture2(); + 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 (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { + if (!this._emissiveTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (MaterialFlags.SpecularTextureEnabled) { + if (this._metallicTexture) { + if (!this._metallicTexture.isReadyOrNotBlocking()) { + return false; + } + } else if (this._reflectivityTexture) { + if (!this._reflectivityTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._metallicReflectanceTexture) { + if (!this._metallicReflectanceTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._reflectanceTexture) { + if (!this._reflectanceTexture.isReadyOrNotBlocking()) { + return false; + } + } + + if (this._microSurfaceTexture) { + if (!this._microSurfaceTexture.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("PBR2Material: 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("vAlbedoInfos", 2); + ubo.addUniform("vBaseWeightInfos", 2); + ubo.addUniform("vBaseDiffuseRoughnessInfos", 2); + ubo.addUniform("vAmbientInfos", 4); + ubo.addUniform("vOpacityInfos", 2); + ubo.addUniform("vEmissiveInfos", 2); + ubo.addUniform("vLightmapInfos", 2); + ubo.addUniform("vReflectivityInfos", 3); + ubo.addUniform("vMicroSurfaceSamplerInfos", 2); + ubo.addUniform("vBumpInfos", 3); + ubo.addUniform("albedoMatrix", 16); + ubo.addUniform("baseWeightMatrix", 16); + ubo.addUniform("baseDiffuseRoughnessMatrix", 16); + ubo.addUniform("ambientMatrix", 16); + ubo.addUniform("opacityMatrix", 16); + ubo.addUniform("emissiveMatrix", 16); + ubo.addUniform("lightmapMatrix", 16); + ubo.addUniform("reflectivityMatrix", 16); + ubo.addUniform("microSurfaceSamplerMatrix", 16); + ubo.addUniform("bumpMatrix", 16); + ubo.addUniform("vTangentSpaceParams", 2); + ubo.addUniform("vAlbedoColor", 4); + ubo.addUniform("baseWeight", 1); + ubo.addUniform("baseDiffuseRoughness", 1); + ubo.addUniform("vLightingIntensity", 4); + + ubo.addUniform("pointSize", 1); + ubo.addUniform("vReflectivityColor", 4); + ubo.addUniform("vEmissiveColor", 3); + ubo.addUniform("vAmbientColor", 3); + + ubo.addUniform("vDebugMode", 2); + + ubo.addUniform("vMetallicReflectanceFactors", 4); + ubo.addUniform("vMetallicReflectanceInfos", 2); + ubo.addUniform("metallicReflectanceMatrix", 16); + ubo.addUniform("vReflectanceInfos", 2); + ubo.addUniform("reflectanceMatrix", 16); + + ubo.addUniform("cameraInfo", 4); + PrepareUniformLayoutForIBL(ubo, true, true, true, true, true); + 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) { + if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + ubo.updateFloat2("vAlbedoInfos", this._albedoTexture.coordinatesIndex, this._albedoTexture.level); + BindTextureMatrix(this._albedoTexture, ubo, "albedo"); + } + + if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { + ubo.updateFloat2("vBaseWeightInfos", this._baseWeightTexture.coordinatesIndex, this._baseWeightTexture.level); + BindTextureMatrix(this._baseWeightTexture, ubo, "baseWeight"); + } + + if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { + ubo.updateFloat2("vBaseDiffuseRoughnessInfos", this._baseDiffuseRoughnessTexture.coordinatesIndex, this._baseDiffuseRoughnessTexture.level); + BindTextureMatrix(this._baseDiffuseRoughnessTexture, ubo, "baseDiffuseRoughness"); + } + + if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { + ubo.updateFloat4( + "vAmbientInfos", + this._ambientTexture.coordinatesIndex, + this._ambientTexture.level, + this._ambientTextureStrength, + this._ambientTextureImpactOnAnalyticalLights + ); + BindTextureMatrix(this._ambientTexture, ubo, "ambient"); + } + + if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { + ubo.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level); + BindTextureMatrix(this._opacityTexture, ubo, "opacity"); + } + + if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { + ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); + BindTextureMatrix(this._emissiveTexture, ubo, "emissive"); + } + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level); + BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); + } + + if (MaterialFlags.SpecularTextureEnabled) { + if (this._metallicTexture) { + ubo.updateFloat3("vReflectivityInfos", this._metallicTexture.coordinatesIndex, this._metallicTexture.level, this._ambientTextureStrength); + BindTextureMatrix(this._metallicTexture, ubo, "reflectivity"); + } else if (this._reflectivityTexture) { + ubo.updateFloat3("vReflectivityInfos", this._reflectivityTexture.coordinatesIndex, this._reflectivityTexture.level, 1.0); + BindTextureMatrix(this._reflectivityTexture, ubo, "reflectivity"); + } + + if (this._metallicReflectanceTexture) { + ubo.updateFloat2("vMetallicReflectanceInfos", this._metallicReflectanceTexture.coordinatesIndex, this._metallicReflectanceTexture.level); + BindTextureMatrix(this._metallicReflectanceTexture, ubo, "metallicReflectance"); + } + + if (this._reflectanceTexture && defines.REFLECTANCE) { + ubo.updateFloat2("vReflectanceInfos", this._reflectanceTexture.coordinatesIndex, this._reflectanceTexture.level); + BindTextureMatrix(this._reflectanceTexture, ubo, "reflectance"); + } + + if (this._microSurfaceTexture) { + ubo.updateFloat2("vMicroSurfaceSamplerInfos", this._microSurfaceTexture.coordinatesIndex, this._microSurfaceTexture.level); + BindTextureMatrix(this._microSurfaceTexture, ubo, "microSurfaceSampler"); + } + } + + 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); + } + + // Colors + if (defines.METALLICWORKFLOW) { + TmpColors.Color4[0].r = this._metallic === undefined || this._metallic === null ? 1 : this._metallic; + TmpColors.Color4[0].g = this._roughness === undefined || this._roughness === null ? 1 : this._roughness; + const ior = 1.5; + const outsideIOR = 1; // consider air as clear coat and other layers would remap in the shader. + TmpColors.Color4[0].b = ior; + // We are here deriving our default reflectance from a common value for none metallic surface. + // Based of the schlick fresnel approximation model + // for dielectrics. + const f0 = Math.pow((ior - outsideIOR) / (ior + outsideIOR), 2); + TmpColors.Color4[0].a = f0; + ubo.updateDirectColor4("vReflectivityColor", TmpColors.Color4[0]); + ubo.updateColor4("vMetallicReflectanceFactors", this._metallicReflectanceColor, this._metallicF0Factor); + } else { + ubo.updateColor4("vReflectivityColor", this._reflectivityColor, this._microSurface); + } + + ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); + + ubo.updateColor4("vAlbedoColor", this._albedoColor, this.alpha); + + ubo.updateFloat("baseWeight", this._baseWeight); + ubo.updateFloat("baseDiffuseRoughness", this._baseDiffuseRoughness || 0.0); + + // Misc + this._lightingInfos.x = this._directIntensity; + this._lightingInfos.y = this._emissiveIntensity; + this._lightingInfos.z = this._environmentIntensity * scene.environmentIntensity; + this._lightingInfos.w = this._specularIntensity; + + ubo.updateVector4("vLightingIntensity", this._lightingInfos); + + // Colors + scene.ambientColor.multiplyToRef(this._ambientColor, this._globalAmbientColor); + + ubo.updateColor3("vAmbientColor", this._globalAmbientColor); + + ubo.updateFloat2("vDebugMode", this.debugLimit, this.debugFactor); + } + + // Textures + if (scene.texturesEnabled) { + if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + ubo.setTexture("albedoSampler", this._albedoTexture); + } + + if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { + ubo.setTexture("baseWeightSampler", this._baseWeightTexture); } if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { - if (!this._baseDiffuseRoughnessTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("baseDiffuseRoughnessSampler", this._baseDiffuseRoughnessTexture); } if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { - if (!this._ambientTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("ambientSampler", this._ambientTexture); } if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { - if (!this._opacityTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("opacitySampler", this._opacityTexture); } - const reflectionTexture = this._getReflectionTexture2(); - 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; - } - } - } + BindIBLSamplers(scene, defines, ubo, reflectionTexture, this.realTimeFiltering); - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { - if (!this._lightmapTexture.isReadyOrNotBlocking()) { - return false; - } + if (defines.ENVIRONMENTBRDF) { + ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); } if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { - if (!this._emissiveTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("emissiveSampler", this._emissiveTexture); + } + + if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { + ubo.setTexture("lightmapSampler", this._lightmapTexture); } if (MaterialFlags.SpecularTextureEnabled) { if (this._metallicTexture) { - if (!this._metallicTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("reflectivitySampler", this._metallicTexture); } else if (this._reflectivityTexture) { - if (!this._reflectivityTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("reflectivitySampler", this._reflectivityTexture); } if (this._metallicReflectanceTexture) { - if (!this._metallicReflectanceTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("metallicReflectanceSampler", this._metallicReflectanceTexture); } - if (this._reflectanceTexture) { - if (!this._reflectanceTexture.isReadyOrNotBlocking()) { - return false; - } + if (this._reflectanceTexture && defines.REFLECTANCE) { + ubo.setTexture("reflectanceSampler", this._reflectanceTexture); } if (this._microSurfaceTexture) { - if (!this._microSurfaceTexture.isReadyOrNotBlocking()) { - return false; - } + ubo.setTexture("microSurfaceSampler", this._microSurfaceTexture); } } - if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { - // Bump texture cannot be not blocking. - if (!this._bumpTexture.isReady()) { - return false; - } + if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { + ubo.setTexture("bumpSampler", this._bumpTexture); } + } - if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) { - // This is blocking. - if (!this._environmentBRDFTexture.isReady()) { - return false; - } - } + // OIT with depth peeling + if (this.getScene().useOrderIndependentTransparency && this.needAlphaBlendingForMesh(mesh)) { + this.getScene().depthPeelingRenderer!.bind(effect); } - } - this._eventInfo.isReadyForSubMesh = true; - this._eventInfo.defines = defines; - this._eventInfo.subMesh = subMesh; - this._callbackPluginEventIsReadyForSubMesh(this._eventInfo); + this._eventInfo.subMesh = subMesh; + this._callbackPluginEventBindForSubMesh(this._eventInfo); - if (!this._eventInfo.isReadyForSubMesh) { - return false; + // Clip plane + BindClipPlane(this._activeEffect, this, scene); + + this.bindEyePosition(effect); + } else if (scene.getEngine()._features.needToAlwaysBindUniformBuffers) { + this._needToBindSceneUbo = true; } - if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) { - if (!this._imageProcessingConfiguration.isReady()) { - return false; + if (mustRebind || !this.isFrozen) { + // Lights + if (scene.lightsEnabled && !this._disableLighting) { + BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights); } - } - // 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; - } + // 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); } - if (!engine.getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) { - mesh.createNormals(true); - Logger.Warn("PBR2Material: Normals have been created for the mesh: " + mesh.name); + 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(); + + if (this._albedoTexture && this._albedoTexture.animations && this._albedoTexture.animations.length > 0) { + results.push(this._albedoTexture); } - const previousEffect = subMesh.effect; - const lightDisposed = defines._areLightsDisposed; - let effect = this._prepareEffect2(mesh, defines, this.onCompiled, this.onError, useInstances, null, subMesh.getRenderingMesh().hasThinInstances); + if (this._baseWeightTexture && this._baseWeightTexture.animations && this._baseWeightTexture.animations.length > 0) { + results.push(this._baseWeightTexture); + } - let forceWasNotReadyPreviously = false; + if (this._baseDiffuseRoughnessTexture && this._baseDiffuseRoughnessTexture.animations && this._baseDiffuseRoughnessTexture.animations.length > 0) { + results.push(this._baseDiffuseRoughnessTexture); + } - if (effect) { - if (this._onEffectCreatedObservable) { - onCreatedEffectParameters.effect = effect; - onCreatedEffectParameters.subMesh = subMesh; - this._onEffectCreatedObservable.notifyObservers(onCreatedEffectParameters); - } + if (this._ambientTexture && this._ambientTexture.animations && this._ambientTexture.animations.length > 0) { + results.push(this._ambientTexture); + } - // Use previous effect while new one is compiling - if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) { - effect = previousEffect; - defines.markAsUnprocessed(); + if (this._opacityTexture && this._opacityTexture.animations && this._opacityTexture.animations.length > 0) { + results.push(this._opacityTexture); + } - forceWasNotReadyPreviously = this.isFrozen; + if (this._reflectionTexture && this._reflectionTexture.animations && this._reflectionTexture.animations.length > 0) { + results.push(this._reflectionTexture); + } - 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 (this._emissiveTexture && this._emissiveTexture.animations && this._emissiveTexture.animations.length > 0) { + results.push(this._emissiveTexture); + } + + if (this._metallicTexture && this._metallicTexture.animations && this._metallicTexture.animations.length > 0) { + results.push(this._metallicTexture); + } else if (this._reflectivityTexture && this._reflectivityTexture.animations && this._reflectivityTexture.animations.length > 0) { + results.push(this._reflectivityTexture); + } + + 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); + } + + if (this._metallicReflectanceTexture && this._metallicReflectanceTexture.animations && this._metallicReflectanceTexture.animations.length > 0) { + results.push(this._metallicReflectanceTexture); + } + + if (this._reflectanceTexture && this._reflectanceTexture.animations && this._reflectanceTexture.animations.length > 0) { + results.push(this._reflectanceTexture); + } + + if (this._microSurfaceTexture && this._microSurfaceTexture.animations && this._microSurfaceTexture.animations.length > 0) { + results.push(this._microSurfaceTexture); + } + + return results; + } + + /** + * Returns an array of the actively used textures. + * @returns - Array of BaseTextures + */ + public override getActiveTextures(): BaseTexture[] { + const activeTextures = super.getActiveTextures(); + + if (this._albedoTexture) { + activeTextures.push(this._albedoTexture); + } + + if (this._baseWeightTexture) { + activeTextures.push(this._baseWeightTexture); + } + + if (this._baseDiffuseRoughnessTexture) { + activeTextures.push(this._baseDiffuseRoughnessTexture); + } + + if (this._ambientTexture) { + activeTextures.push(this._ambientTexture); + } + + if (this._opacityTexture) { + activeTextures.push(this._opacityTexture); + } + + if (this._reflectionTexture) { + activeTextures.push(this._reflectionTexture); + } + + if (this._emissiveTexture) { + activeTextures.push(this._emissiveTexture); + } + + if (this._reflectivityTexture) { + activeTextures.push(this._reflectivityTexture); + } + + if (this._metallicTexture) { + activeTextures.push(this._metallicTexture); + } + + if (this._metallicReflectanceTexture) { + activeTextures.push(this._metallicReflectanceTexture); + } + + if (this._reflectanceTexture) { + activeTextures.push(this._reflectanceTexture); + } + + if (this._microSurfaceTexture) { + activeTextures.push(this._microSurfaceTexture); + } + + 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; + } + + if (this._albedoTexture === texture) { + return true; + } + + if (this._baseWeightTexture === texture) { + return true; + } + + if (this._baseDiffuseRoughnessTexture === texture) { + return true; + } + + if (this._ambientTexture === texture) { + return true; + } + + if (this._opacityTexture === texture) { + return true; + } + + if (this._reflectionTexture === texture) { + return true; + } + + if (this._emissiveTexture === texture) { + return true; + } + + if (this._reflectivityTexture === texture) { + return true; + } + + if (this._metallicTexture === texture) { + return true; + } + + if (this._metallicReflectanceTexture === texture) { + return true; + } + + if (this._reflectanceTexture === texture) { + return true; + } + + if (this._microSurfaceTexture === 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(); } + + this._albedoTexture?.dispose(); + this._baseWeightTexture?.dispose(); + this._baseDiffuseRoughnessTexture?.dispose(); + this._ambientTexture?.dispose(); + this._opacityTexture?.dispose(); + this._reflectionTexture?.dispose(); + this._emissiveTexture?.dispose(); + this._metallicTexture?.dispose(); + this._reflectivityTexture?.dispose(); + this._bumpTexture?.dispose(); + this._lightmapTexture?.dispose(); + this._metallicReflectanceTexture?.dispose(); + this._reflectanceTexture?.dispose(); + this._microSurfaceTexture?.dispose(); } - if (!subMesh.effect || !subMesh.effect.isReady()) { - return false; + this._renderTargets.dispose(); + + if (this._imageProcessingConfiguration && this._imageProcessingObserver) { + this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); } - defines._renderId = scene.getRenderId(); - drawWrapper._wasPreviouslyReady = forceWasNotReadyPreviously ? false : true; - drawWrapper._wasPreviouslyUsingInstances = !!useInstances; + super.dispose(forceDisposeEffect, forceDisposeTextures); + } - this._checkScenePerformancePriority(); + /** + * 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 true; + return this.getScene().environmentTexture; } - private _prepareEffect2( + private _prepareEffect( mesh: AbstractMesh, defines: PBR2MaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, @@ -1348,7 +2529,7 @@ export class PBR2Material extends PBRBaseMaterial { useClipPlane: Nullable = null, useThinInstances: boolean ): Nullable { - this._prepareDefines2(mesh, defines, useInstances, useClipPlane, useThinInstances); + this._prepareDefines(mesh, defines, useInstances, useClipPlane, useThinInstances); if (!defines.isDirty) { return null; @@ -1605,7 +2786,7 @@ export class PBR2Material extends PBRBaseMaterial { processCodeAfterIncludes: this._eventInfo.customCode, multiTarget: defines.PREPASS, shaderLanguage: this._shaderLanguage, - extraInitializationsAsync: this._shadersLoaded2 + extraInitializationsAsync: this._shadersLoaded ? undefined : async () => { if (this.shaderLanguage === ShaderLanguage.WGSL) { @@ -1614,7 +2795,7 @@ export class PBR2Material extends PBRBaseMaterial { await Promise.all([import("../../Shaders/pbr2.vertex"), import("../../Shaders/pbr2.fragment")]); } - this._shadersLoaded2 = true; + this._shadersLoaded = true; }, }, engine @@ -1625,7 +2806,7 @@ export class PBR2Material extends PBRBaseMaterial { return effect; } - private _prepareDefines2( + private _prepareDefines( mesh: AbstractMesh, defines: PBR2MaterialDefines, useInstances: Nullable = null, @@ -1652,7 +2833,7 @@ export class PBR2Material extends PBRBaseMaterial { MaterialHelperGeometryRendering.PrepareDefines(engine.currentRenderPassId, mesh, defines); // Textures - defines.METALLICWORKFLOW = this.isMetallicWorkflow(); + defines.METALLICWORKFLOW = true; if (defines._areTexturesDirty) { defines._needUVs = false; for (let i = 1; i <= Constants.MAX_SUPPORTED_UV_SETS; ++i) { @@ -1660,6 +2841,8 @@ export class PBR2Material extends PBRBaseMaterial { } if (scene.texturesEnabled) { defines.ALBEDODIRECTUV = 0; + defines.BASE_WEIGHTDIRECTUV = 0; + defines.BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; defines.AMBIENTDIRECTUV = 0; defines.OPACITYDIRECTUV = 0; defines.EMISSIVEDIRECTUV = 0; @@ -1863,9 +3046,18 @@ export class PBR2Material extends PBRBaseMaterial { // Misc. if (defines._areMiscDirty) { - PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines, false); - defines.UNLIT = this._unlit2 || ((this.pointsCloud || this.wireframe) && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)); - defines.DEBUGMODE = this._debugMode2; + 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 @@ -1894,17 +3086,6 @@ export class PBR2Material extends PBRBaseMaterial { return this.getScene().environmentTexture; } - - private _shadersLoaded2 = false; - - /** - * If set to true, no lighting calculations will be applied. - */ - private _unlit2 = false; - - private _debugMode2 = 0; - - private _breakShaderLoadedCheck2 = false; } RegisterClass("BABYLON.PBR2Material", PBR2Material); diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index bb1f8131403..e79fdfc446f 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -1915,7 +1915,7 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { ubo.addUniform("reflectanceMatrix", 16); ubo.addUniform("cameraInfo", 4); - PrepareUniformLayoutForIBL(ubo, true, true, true); + PrepareUniformLayoutForIBL(ubo, true, true, true, true, true); super.buildUniformLayout(); } @@ -2062,7 +2062,7 @@ export abstract class PBRBaseMaterial extends PBRBaseMaterialBase { } } - BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, this._reflectionColor); + BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, true, true, true, true, true, this._reflectionColor); // Point size if (this.pointsCloud) { diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index 829693b1330..5d7f718e7d3 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -276,6 +276,11 @@ export function BindSceneUniformBuffer(effect: Effect, sceneUbo: UniformBuffer): * @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( @@ -284,6 +289,11 @@ export function BindIBLParameters( 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) { @@ -291,7 +301,7 @@ export function BindIBLParameters( ubo.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix()); ubo.updateFloat2("vReflectionInfos", reflectionTexture.level * scene.iblIntensity, 0); - if ((reflectionTexture).boundingBoxSize) { + if (supportLocalProjection && (reflectionTexture).boundingBoxSize) { const cubeTexture = reflectionTexture; ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition); @@ -303,7 +313,7 @@ export function BindIBLParameters( ubo.updateFloat2("vReflectionFilteringInfo", width, Math.log2(width)); } - if (!defines.USEIRRADIANCEMAP) { + if (supportSH && !defines.USEIRRADIANCEMAP) { const polynomials = reflectionTexture.sphericalPolynomial; if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) { if (defines.SPHERICAL_HARMONICS) { @@ -329,17 +339,21 @@ export function BindIBLParameters( ubo.updateFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z); } } - } else { + } 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!); } } - ubo.updateFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset); + if (supportTextureInfo) { + ubo.updateFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset); + } } } - ubo.updateColor3("vReflectionColor", reflectionColor); + if (useColor) { + ubo.updateColor3("vReflectionColor", reflectionColor); + } } /** @@ -1478,15 +1492,17 @@ export function PrepareUniformsAndSamplersList(uniformsListOrOptions: string[] | * @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 useAdvanced Add advanced uniforms for IBL 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, - useAdvanced: boolean = false, - supportSH: boolean = false + usePBR: boolean = false, + supportSH: boolean = false, + useColor: boolean = false ): void { ubo.addUniform("vReflectionInfos", 2); ubo.addUniform("reflectionMatrix", 16); @@ -1499,12 +1515,15 @@ export function PrepareUniformLayoutForIBL( ubo.addUniform("vReflectionSize", 3); } - if (useAdvanced) { + if (usePBR) { ubo.addUniform("vReflectionFilteringInfo", 2); - ubo.addUniform("vReflectionColor", 3); ubo.addUniform("vReflectionDominantDirection", 3); } + if (useColor) { + ubo.addUniform("vReflectionColor", 3); + } + if (supportSH) { ubo.addUniform("vSphericalL00", 3); ubo.addUniform("vSphericalL1_1", 3); diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 5aa4f555225..8d61ed126fe 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -1470,7 +1470,7 @@ export class StandardMaterial extends StandardMaterialBase { ubo.updateFloat("alphaCutOff", this.alphaCutOff); } - BindIBLParameters(scene, defines, ubo, this._reflectionTexture); + 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/Shaders/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx index 5842558c3ce..ccfbcae5566 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx @@ -67,8 +67,8 @@ uniform Material { vec3 vReflectionPosition; vec3 vReflectionSize; vec2 vReflectionFilteringInfo; - vec3 vReflectionColor; vec3 vReflectionDominantDirection; + vec3 vReflectionColor; vec3 vSphericalL00; vec3 vSphericalL1_1; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx index f5aeed5f908..3f434da4696 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx @@ -42,8 +42,8 @@ uniform vReflectionMicrosurfaceInfos: vec3f; uniform vReflectionPosition: vec3f; uniform vReflectionSize: vec3f; uniform vReflectionFilteringInfo: vec2f; -uniform vReflectionColor: vec3f; uniform vReflectionDominantDirection: vec3f; +uniform vReflectionColor: vec3f; uniform vSphericalL00: vec3f; uniform vSphericalL1_1: vec3f; 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 2029a3aaf1f..0044eb966b6 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 @@ -81,7 +81,9 @@ export class EXT_materials_diffuse_roughness implements IGLTFLoaderExtension { 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 2a89f37a970..c425c295da5 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,6 +1,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -71,7 +70,7 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } private async _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsAnisotropy, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 438c5e49dda..bc394cd1040 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,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -73,7 +72,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 88185371315..5507ebfb1ab 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,7 +1,6 @@ /* eslint-disable github/no-then */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -78,7 +77,7 @@ 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 c4d12526646..1a99485b358 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,7 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -74,7 +73,7 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { 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 b7aefce1d72..ad70f99ba58 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,6 +1,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -78,7 +77,7 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 1c9a62c37eb..11168af02da 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,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -73,7 +72,7 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 c4d3aba8b9e..4816792a5e3 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,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -75,7 +74,7 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 a11e95c6f56..5f91a41d555 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,6 +1,5 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -379,7 +378,7 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const pbrMaterial = babylonMaterial; 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 513052f2896..349cbd67c10 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,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -82,7 +81,7 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } From 72b9b3cedae621cd1c78d8d9695151a644881a5b Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 24 Jun 2025 15:23:51 -0700 Subject: [PATCH 09/45] Rename PBR2 to OpenPBR --- packages/dev/core/src/Materials/PBR/index.ts | 10 ++-- .../{pbr2Material.ts => openPbrMaterial.ts} | 57 +++++++++---------- .../{pbr2.fragment.fx => openpbr.fragment.fx} | 0 .../{pbr2.vertex.fx => openpbr.vertex.fx} | 1 + .../{pbr2.fragment.fx => openpbr.fragment.fx} | 0 .../{pbr2.vertex.fx => openpbr.vertex.fx} | 0 .../EXT_materials_diffuse_roughness.ts | 4 +- .../KHR_materials_emissive_strength.ts | 4 +- .../KHR_materials_pbrSpecularGlossiness.ts | 4 +- .../2.0/Extensions/KHR_materials_specular.ts | 4 +- .../2.0/Extensions/KHR_materials_unlit.ts | 4 +- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 4 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 4 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 10 ++-- 14 files changed, 53 insertions(+), 53 deletions(-) rename packages/dev/core/src/Materials/PBR/{pbr2Material.ts => openPbrMaterial.ts} (95%) rename packages/dev/core/src/Shaders/{pbr2.fragment.fx => openpbr.fragment.fx} (100%) rename packages/dev/core/src/Shaders/{pbr2.vertex.fx => openpbr.vertex.fx} (97%) rename packages/dev/core/src/ShadersWGSL/{pbr2.fragment.fx => openpbr.fragment.fx} (100%) rename packages/dev/core/src/ShadersWGSL/{pbr2.vertex.fx => openpbr.vertex.fx} (100%) diff --git a/packages/dev/core/src/Materials/PBR/index.ts b/packages/dev/core/src/Materials/PBR/index.ts index c97b2aa4adc..1137c63f604 100644 --- a/packages/dev/core/src/Materials/PBR/index.ts +++ b/packages/dev/core/src/Materials/PBR/index.ts @@ -5,7 +5,7 @@ export * from "./pbrBRDFConfiguration"; export * from "./pbrClearCoatConfiguration"; export * from "./pbrIridescenceConfiguration"; export * from "./pbrMaterial"; -export * from "./pbr2Material"; +export * from "./openPbrMaterial"; export * from "./pbrMetallicRoughnessMaterial"; export * from "./pbrSpecularGlossinessMaterial"; export * from "./pbrSheenConfiguration"; @@ -16,7 +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/pbr2.vertex"; -export * from "../../ShadersWGSL/pbr2.fragment"; -export * from "../../Shaders/pbr2.vertex"; -export * from "../../Shaders/pbr2.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/pbr2Material.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts similarity index 95% rename from packages/dev/core/src/Materials/PBR/pbr2Material.ts rename to packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 1d08c1d3969..c0869b94d73 100644 --- a/packages/dev/core/src/Materials/PBR/pbr2Material.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -67,7 +67,7 @@ import type { IAnimatable } from "../../Animations/animatable.interface"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; /** - * Defines a property for the PBR2Material. + * Defines a property for the OpenPBRMaterial. */ class Property { /** @@ -110,12 +110,12 @@ class Sampler { ) {} } -class PBR2MaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} +class OpenPBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} /** * Manages the defines for the PBR Material. * @internal */ -export class PBR2MaterialDefines extends ImageProcessingDefinesMixin(PBR2MaterialDefinesBase) { +export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRMaterialDefinesBase) { public PBR = true; public NUM_SAMPLES = "0"; @@ -330,8 +330,7 @@ export class PBR2MaterialDefines extends ImageProcessingDefinesMixin(PBR2Materia } } -class PBR2BaseMaterial extends ImageProcessingMixin(PushMaterial) {} -// class PBR2MaterialBase extends ImageProcessingMixin(PBRBaseMaterial) {} +class OpenPBRMaterialBase extends ImageProcessingMixin(PushMaterial) {} /** * The Physically based material of BJS. * @@ -339,24 +338,24 @@ class PBR2BaseMaterial extends ImageProcessingMixin(PushMaterial) {} * For more information, please refer to the documentation : * https://doc.babylonjs.com/features/featuresDeepDive/materials/using/introToPBR */ -export class PBR2Material extends PBR2BaseMaterial { +export class OpenPBRMaterial extends OpenPBRMaterialBase { /** - * PBR2MaterialTransparencyMode: No transparency mode, Alpha channel is not use. + * OpenPBRMaterialTransparencyMode: No transparency mode, Alpha channel is not use. */ public static readonly PBRMATERIAL_OPAQUE = PBRBaseMaterial.PBRMATERIAL_OPAQUE; /** - * PBR2MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value. + * 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; /** - * PBR2MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + * 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; /** - * PBR2MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer. + * 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; @@ -470,7 +469,7 @@ export class PBR2Material extends PBR2BaseMaterial { */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientTextureImpactOnAnalyticalLights: number = PBR2Material.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; + public ambientTextureImpactOnAnalyticalLights: number = OpenPBRMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; /** * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true. @@ -1488,7 +1487,7 @@ export class PBR2Material extends PBR2BaseMaterial { protected _cacheHasRenderTargetTextures = false; /** - * Instantiates a new PBR2Material instance. + * Instantiates a new OpenPBRMaterial instance. * * @param name The material name * @param scene The scene the material will be use in. @@ -1540,7 +1539,7 @@ export class PBR2Material extends PBR2BaseMaterial { * @returns the name of the material class. */ public override getClassName(): string { - return "PBR2Material"; + return "OpenPBRMaterial"; } /** @@ -1604,8 +1603,8 @@ export class PBR2Material extends PBR2BaseMaterial { * @param rootUrl defines the root URL to use to load textures * @returns cloned material instance */ - public override clone(name: string, cloneTexturesOnlyOnce: boolean = true, rootUrl = ""): PBR2Material { - const clone = SerializationHelper.Clone(() => new PBR2Material(name, this.getScene()), this, { cloneTexturesOnlyOnce }); + 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; @@ -1623,7 +1622,7 @@ export class PBR2Material extends PBR2BaseMaterial { */ public override serialize(): any { const serializationObject = super.serialize(); - serializationObject.customType = "BABYLON.PBR2Material"; + serializationObject.customType = "BABYLON.OpenPBRMaterial"; return serializationObject; } @@ -1634,10 +1633,10 @@ export class PBR2Material extends PBR2BaseMaterial { * @param source - Serialized object. * @param scene - BJS scene instance. * @param rootUrl - url for the scene object - * @returns - PBR2Material + * @returns - OpenPBRMaterial */ - public static override Parse(source: any, scene: Scene, rootUrl: string): PBR2Material { - const material = SerializationHelper.Parse(() => new PBR2Material(source.name, scene), source, scene, rootUrl); + 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); @@ -1670,7 +1669,7 @@ export class PBR2Material extends PBR2BaseMaterial { if (this._breakShaderLoadedCheck) { return; } - const defines = new PBR2MaterialDefines(this._eventInfo.defineNames); + const defines = new OpenPBRMaterialDefines(this._eventInfo.defineNames); const effect = this._prepareEffect(mesh, defines, undefined, undefined, localOptions.useInstances, localOptions.clipPlane, mesh.hasThinInstances)!; if (this._onEffectCreatedObservable) { onCreatedEffectParameters.effect = effect; @@ -1714,10 +1713,10 @@ export class PBR2Material extends PBR2BaseMaterial { if (!subMesh.materialDefines) { this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); - subMesh.materialDefines = new PBR2MaterialDefines(this._eventInfo.defineNames); + subMesh.materialDefines = new OpenPBRMaterialDefines(this._eventInfo.defineNames); } - const defines = subMesh.materialDefines; + const defines = subMesh.materialDefines; if (this._isReadyForSubMesh(subMesh)) { return true; } @@ -1861,7 +1860,7 @@ export class PBR2Material extends PBR2BaseMaterial { if (!engine.getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) { mesh.createNormals(true); - Logger.Warn("PBR2Material: Normals have been created for the mesh: " + mesh.name); + Logger.Warn("OpenPBRMaterial: Normals have been created for the mesh: " + mesh.name); } const previousEffect = subMesh.effect; @@ -1967,7 +1966,7 @@ export class PBR2Material extends PBR2BaseMaterial { public override bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void { const scene = this.getScene(); - const defines = subMesh.materialDefines; + const defines = subMesh.materialDefines; if (!defines) { return; } @@ -2522,7 +2521,7 @@ export class PBR2Material extends PBR2BaseMaterial { private _prepareEffect( mesh: AbstractMesh, - defines: PBR2MaterialDefines, + defines: OpenPBRMaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, useInstances: Nullable = null, @@ -2790,9 +2789,9 @@ export class PBR2Material extends PBR2BaseMaterial { ? undefined : async () => { if (this.shaderLanguage === ShaderLanguage.WGSL) { - await Promise.all([import("../../ShadersWGSL/pbr2.vertex"), import("../../ShadersWGSL/pbr2.fragment")]); + await Promise.all([import("../../ShadersWGSL/openpbr.vertex"), import("../../ShadersWGSL/openpbr.fragment")]); } else { - await Promise.all([import("../../Shaders/pbr2.vertex"), import("../../Shaders/pbr2.fragment")]); + await Promise.all([import("../../Shaders/openpbr.vertex"), import("../../Shaders/openpbr.fragment")]); } this._shadersLoaded = true; @@ -2808,7 +2807,7 @@ export class PBR2Material extends PBR2BaseMaterial { private _prepareDefines( mesh: AbstractMesh, - defines: PBR2MaterialDefines, + defines: OpenPBRMaterialDefines, useInstances: Nullable = null, useClipPlane: Nullable = null, useThinInstances: boolean = false @@ -3088,4 +3087,4 @@ export class PBR2Material extends PBR2BaseMaterial { } } -RegisterClass("BABYLON.PBR2Material", PBR2Material); +RegisterClass("BABYLON.OpenPBRMaterial", OpenPBRMaterial); diff --git a/packages/dev/core/src/Shaders/pbr2.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/pbr2.fragment.fx rename to packages/dev/core/src/Shaders/openpbr.fragment.fx diff --git a/packages/dev/core/src/Shaders/pbr2.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx similarity index 97% rename from packages/dev/core/src/Shaders/pbr2.vertex.fx rename to packages/dev/core/src/Shaders/openpbr.vertex.fx index 778fa33de08..c35a32bf701 100644 --- a/packages/dev/core/src/Shaders/pbr2.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -95,6 +95,7 @@ varying vec3 vPositionW; varying vec4 vColor; #endif +// This is just including TBN, if needed. "Bump" isn't really a great name. #include #include #include diff --git a/packages/dev/core/src/ShadersWGSL/pbr2.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/pbr2.fragment.fx rename to packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/pbr2.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/pbr2.vertex.fx rename to packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx 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 0044eb966b6..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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -75,7 +75,7 @@ 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 15b30b78e65..47785510fe7 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -71,7 +71,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts index 54081698e17..d342c82d3ff 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts @@ -1,7 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -75,7 +75,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax private _loadSpecularGlossinessPropertiesAsync(context: string, properties: IKHRMaterialsPbrSpecularGlossiness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 25d7d3ccf8b..a55f058dca1 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,6 +1,6 @@ import type { Nullable } from "core/types"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -84,7 +84,7 @@ 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 15a0390af36..cae66552046 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,7 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -69,7 +69,7 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension { // 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 82a6559ba80..f52207f3e74 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -48,7 +48,7 @@ export class MSFT_minecraftMesh implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { 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 f45fc79ed69..aaff3b5b7ec 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -48,7 +48,7 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtraAsync(context, material, this.name, async (extraContext, extra) => { if (extra) { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${extraContext}: Material type not supported`); } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index f3a2fd646bd..24a2f2a47dc 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -17,7 +17,7 @@ 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 { PBR2Material } from "core/Materials/PBR/pbr2Material"; +import { 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"; @@ -2128,7 +2128,7 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } @@ -2230,7 +2230,7 @@ export class GLTFLoader implements IGLTFLoader { this._babylonScene._blockEntityCollection = !!this._assetContainer; let babylonMaterial; if (this.parent.usePBR2) { - babylonMaterial = new PBR2Material(name, this._babylonScene); + babylonMaterial = new OpenPBRMaterial(name, this._babylonScene); } else { babylonMaterial = new PBRMaterial(name, this._babylonScene); } @@ -2301,7 +2301,7 @@ 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) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } @@ -2366,7 +2366,7 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof PBR2Material)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } From 189cd015741707e760cae75db35533ecbfab87a3 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 25 Jun 2025 13:37:06 -0700 Subject: [PATCH 10/45] Minor changes --- .../core/src/Materials/PBR/openPbrMaterial.ts | 6 ++-- .../core/src/Materials/PBR/pbrBaseMaterial.ts | 20 ++++++------- .../dev/core/src/Materials/imageProcessing.ts | 8 +++--- .../dev/core/src/Shaders/openpbr.vertex.fx | 28 ------------------- 4 files changed, 16 insertions(+), 46 deletions(-) diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index c0869b94d73..3eec674b50a 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -5,7 +5,7 @@ import type { Nullable } from "../../types"; import { Scene } from "../../scene"; import { Color3, Color4, TmpColors } from "../../Maths/math.color"; import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; -import type { BaseTexture } from "../Textures/baseTexture"; +import type { BaseTexture } from "../../Materials/Textures/baseTexture"; import { PBRBaseMaterial } from "./pbrBaseMaterial"; import { RegisterClass } from "../../Misc/typeStore"; import { Material } from "../material"; @@ -166,7 +166,7 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public MICROSURFACEMAP = false; public MICROSURFACEMAPDIRECTUV = 0; - public METALLICWORKFLOW = false; + public METALLICWORKFLOW = true; public ROUGHNESSSTOREINMETALMAPALPHA = false; public ROUGHNESSSTOREINMETALMAPGREEN = false; public METALLNESSSTOREINMETALMAPBLUE = false; @@ -2121,8 +2121,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { TmpColors.Color4[0].a = f0; ubo.updateDirectColor4("vReflectivityColor", TmpColors.Color4[0]); ubo.updateColor4("vMetallicReflectanceFactors", this._metallicReflectanceColor, this._metallicF0Factor); - } else { - ubo.updateColor4("vReflectivityColor", this._reflectivityColor, this._microSurface); } ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index e79fdfc446f..87e78f6bd7f 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -15,23 +15,23 @@ import { PBRBRDFConfiguration } from "./pbrBRDFConfiguration"; import { PrePassConfiguration } from "../prePassConfiguration"; import { Color3, TmpColors } from "../../Maths/math.color"; -import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines"; -import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; -import type { Effect, IEffectCreationOptions } from "../effect"; -import type { IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../material"; -import { Material } from "../material"; +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"; +import { Material } from "../../Materials/material"; import { MaterialPluginEvent } from "../materialPluginEvent"; -import { MaterialDefines } from "../materialDefines"; -import { PushMaterial } from "../pushMaterial"; +import { MaterialDefines } from "../../Materials/materialDefines"; +import { PushMaterial } from "../../Materials/pushMaterial"; -import type { BaseTexture } from "../Textures/baseTexture"; -import type { RenderTargetTexture } from "../Textures/renderTargetTexture"; +import type { BaseTexture } from "../../Materials/Textures/baseTexture"; +import type { RenderTargetTexture } from "../../Materials/Textures/renderTargetTexture"; import { MaterialFlags } from "../materialFlags"; import { Constants } from "../../Engines/constants"; import type { IAnimatable } from "../../Animations/animatable.interface"; -import "../Textures/baseTexture.polynomial"; +import "../../Materials/Textures/baseTexture.polynomial"; import { EffectFallbacks } from "../effectFallbacks"; import { PBRClearCoatConfiguration } from "./pbrClearCoatConfiguration"; diff --git a/packages/dev/core/src/Materials/imageProcessing.ts b/packages/dev/core/src/Materials/imageProcessing.ts index 7b9f29727f1..ab9d8f5da2d 100644 --- a/packages/dev/core/src/Materials/imageProcessing.ts +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -3,12 +3,12 @@ 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 "./Textures/baseTexture"; -import type { ColorCurves } from "./colorCurves"; +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"; +// export type { Observer } from "../Misc/observable"; +// export type { ColorCurves } from "./colorCurves"; type Constructor = new (...args: any[]) => T; diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index c35a32bf701..46a3f34338c 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -48,34 +48,6 @@ attribute vec4 color; #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy) -#endif - -#ifdef SUBSURFACE - #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness) - #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity) - #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity) - #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor) -#endif - // Output varying vec3 vPositionW; #if DEBUGMODE > 0 From 3478433c845c2e507b721b080e384b2899d7701e Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Thu, 26 Jun 2025 13:22:36 -0700 Subject: [PATCH 11/45] Fixes for OpenPBRMaterial. --- .../core/src/Materials/PBR/openPbrMaterial.ts | 13 +- .../IBLShadows/iblShadowsPluginMaterial.ts | 45 +- .../IBLShadows/iblShadowsRenderPipeline.ts | 3 +- .../ShadersInclude/openPbrUboDeclaration.fx | 98 ++ .../ShadersInclude/pbrUboDeclaration.fx | 3 +- .../ShadersInclude/openPbrUboDeclaration.fx | 73 + .../ShadersInclude/pbrUboDeclaration.fx | 3 +- .../core/src/ShadersWGSL/openpbr.fragment.fx | 2 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 2 +- .../tabs/propertyGridTabComponent.tsx | 12 + .../pbrMaterialPropertyGridComponent.tsx | 1252 +++++++++-------- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 2 +- .../dev/loaders/src/glTF/glTFFileLoader.ts | 4 +- .../sandbox/src/tools/environmentTools.ts | 3 +- 14 files changed, 890 insertions(+), 625 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 3eec674b50a..177005cc765 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -310,6 +310,17 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM 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 @@ -2646,7 +2657,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { PrepareAttributesForMorphTargets(attribs, mesh, defines); PrepareAttributesForBakedVertexAnimation(attribs, mesh, defines); - let shaderName = "pbr2"; + let shaderName = "openpbr"; const uniforms = [ "world", 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/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx new file mode 100644 index 00000000000..cddb7c45b7a --- /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 vAlbedoInfos; + vec2 vBaseWeightInfos; + vec2 vBaseDiffuseRoughnessInfos; + vec4 vAmbientInfos; + vec2 vOpacityInfos; + vec2 vEmissiveInfos; + vec2 vLightmapInfos; + vec3 vReflectivityInfos; + vec2 vMicroSurfaceSamplerInfos; + vec3 vBumpInfos; + mat4 albedoMatrix; + mat4 baseWeightMatrix; + mat4 baseDiffuseRoughnessMatrix; + mat4 ambientMatrix; + mat4 opacityMatrix; + mat4 emissiveMatrix; + mat4 lightmapMatrix; + mat4 reflectivityMatrix; + mat4 microSurfaceSamplerMatrix; + mat4 bumpMatrix; + vec2 vTangentSpaceParams; + vec4 vAlbedoColor; + float baseWeight; + float baseDiffuseRoughness; + vec4 vLightingIntensity; + float pointSize; + vec4 vReflectivityColor; + vec3 vEmissiveColor; + vec3 vAmbientColor; + + vec2 vDebugMode; + + vec4 vMetallicReflectanceFactors; + vec2 vMetallicReflectanceInfos; + 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; + 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; + + #define ADDITIONAL_UBO_DECLARATION +}; + +#include +#include diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx index ccfbcae5566..cddb7c45b7a 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrUboDeclaration.fx @@ -60,6 +60,7 @@ uniform Material { mat4 metallicReflectanceMatrix; vec2 vReflectanceInfos; mat4 reflectanceMatrix; + vec4 cameraInfo; vec2 vReflectionInfos; mat4 reflectionMatrix; @@ -90,8 +91,6 @@ uniform Material { vec3 vSphericalYZ; vec3 vSphericalZX; - vec4 cameraInfo; - #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..6eacae512da --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -0,0 +1,73 @@ +uniform vAlbedoInfos: vec2f; +uniform vBaseWeightInfos: vec2f; +uniform vBaseDiffuseRoughnessInfos: vec2f; +uniform vAmbientInfos: vec4f; +uniform vOpacityInfos: vec2f; +uniform vEmissiveInfos: vec2f; +uniform vLightmapInfos: vec2f; +uniform vReflectivityInfos: vec3f; +uniform vMicroSurfaceSamplerInfos: vec2f; +uniform vBumpInfos: vec3f; +uniform albedoMatrix: mat4x4f; +uniform baseWeightMatrix: mat4x4f; +uniform baseDiffuseRoughnessMatrix: mat4x4f; +uniform ambientMatrix: mat4x4f; +uniform opacityMatrix: mat4x4f; +uniform emissiveMatrix: mat4x4f; +uniform lightmapMatrix: mat4x4f; +uniform reflectivityMatrix: mat4x4f; +uniform microSurfaceSamplerMatrix: mat4x4f; +uniform bumpMatrix: mat4x4f; +uniform vTangentSpaceParams: vec2f; +uniform vAlbedoColor: vec4f; +uniform baseWeight: f32; +uniform baseDiffuseRoughness: f32; +uniform vLightingIntensity: vec4f; +uniform pointSize: f32; +uniform vReflectivityColor: vec4f; +uniform vEmissiveColor: vec3f; +uniform vAmbientColor: vec3f; + +uniform vDebugMode: vec2f; + +uniform vMetallicReflectanceFactors: vec4f; +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; +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; + +#define ADDITIONAL_UBO_DECLARATION + + +#include +#include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx index 3f434da4696..6eacae512da 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrUboDeclaration.fx @@ -35,6 +35,7 @@ uniform vMetallicReflectanceInfos: vec2f; uniform metallicReflectanceMatrix: mat4x4f; uniform vReflectanceInfos: vec2f; uniform reflectanceMatrix: mat4x4f; +uniform cameraInfo: vec4f; uniform vReflectionInfos: vec2f; uniform reflectionMatrix: mat4x4f; @@ -65,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 index 91bae999b44..83f4b634711 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -11,7 +11,7 @@ #endif // Declaration -#include +#include #include #include[0..maxSimultaneousLights] diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index dd7d851f241..11eea0f2e3d 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -1,6 +1,6 @@ #define PBR_VERTEX_SHADER -#include +#include #define CUSTOM_VERTEX_BEGIN diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index d67eb582f9c..0d2dd7ca61a 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 { 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..457913824eb 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; @@ -86,14 +87,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component - + {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 && ( - - 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/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 24a2f2a47dc..a772397e428 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -2229,7 +2229,7 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; let babylonMaterial; - if (this.parent.usePBR2) { + if (this.parent.useOpenPBR) { babylonMaterial = new OpenPBRMaterial(name, this._babylonScene); } else { babylonMaterial = new PBRMaterial(name, this._babylonScene); diff --git a/packages/dev/loaders/src/glTF/glTFFileLoader.ts b/packages/dev/loaders/src/glTF/glTFFileLoader.ts index 38f287c9d7b..2e0e712506b 100644 --- a/packages/dev/loaders/src/glTF/glTFFileLoader.ts +++ b/packages/dev/loaders/src/glTF/glTFFileLoader.ts @@ -206,7 +206,7 @@ abstract class GLTFLoaderOptions { this.compileShadowGenerators = options.compileShadowGenerators ?? this.compileShadowGenerators; this.transparencyAsCoverage = options.transparencyAsCoverage ?? this.transparencyAsCoverage; this.useRangeRequests = options.useRangeRequests ?? this.useRangeRequests; - this.usePBR2 = options.usePBR2 ?? this.usePBR2; + this.useOpenPBR = options.useOpenPBR ?? this.useOpenPBR; this.createInstances = options.createInstances ?? this.createInstances; this.alwaysComputeBoundingBox = options.alwaysComputeBoundingBox ?? this.alwaysComputeBoundingBox; this.loadAllMaterials = options.loadAllMaterials ?? this.loadAllMaterials; @@ -298,7 +298,7 @@ abstract class GLTFLoaderOptions { /** * Load the glTF files using the PBR2 material. */ - public usePBR2 = false; + 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) { From 12eef7f12ed713c30eee6f42ffed59e666600a08 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 9 Jul 2025 18:32:30 -0700 Subject: [PATCH 12/45] Adding properties to OpenPBRMaterial --- .../core/src/Materials/PBR/openPbrMaterial.ts | 579 ++++++++++-------- packages/dev/core/src/Misc/decorators.ts | 30 + .../ShadersInclude/openPbrUboDeclaration.fx | 24 +- .../openpbrFragmentDeclaration.fx | 254 ++++++++ .../openpbrFragmentSamplersDeclaration.fx | 124 ++++ .../openpbrVertexDeclaration.fx | 206 +++++++ .../ShadersInclude/pbrBRDFFunctions.fx | 2 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 26 +- .../dev/core/src/Shaders/openpbr.vertex.fx | 4 +- .../ShadersInclude/openPbrUboDeclaration.fx | 23 +- .../openpbrFragmentSamplersDeclaration.fx | 134 ++++ .../ShadersInclude/pbrBRDFFunctions.fx | 2 +- .../core/src/ShadersWGSL/openpbr.fragment.fx | 26 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 6 +- .../tabs/propertyGridTabComponent.tsx | 2 +- .../pbrMaterialPropertyGridComponent.tsx | 18 +- .../KHR_materials_pbrSpecularGlossiness.ts | 18 +- .../2.0/Extensions/KHR_materials_unlit.ts | 19 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 10 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 39 +- 20 files changed, 1200 insertions(+), 346 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 177005cc765..534ba8992c4 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture } from "../../Misc/decorators"; +import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, addAccessorsForMaterialProperty } from "../../Misc/decorators"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import { Scene } from "../../scene"; @@ -55,7 +55,7 @@ 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 } from "core/Maths/math.vector"; +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"; @@ -66,28 +66,79 @@ 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 value The current value of the property, defaults to defaultValue - */ - constructor( - public name: string, - public defaultValue: T, - public value: T = defaultValue - ) {} + * @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 type. + * 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; // Single float + return 1; } else if (this.defaultValue instanceof Color3) { return 3; } else if (this.defaultValue instanceof Color4) { @@ -104,10 +155,50 @@ class Property { } class Sampler { - constructor( - public name: string, // Name in the shader - public value: Nullable = null // Texture value, default to null - ) {} + 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 this.samplerPrefix + "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) {} @@ -128,7 +219,9 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public VERTEXCOLOR = false; public BASE_WEIGHT = false; + public BASE_WEIGHTDIRECTUV = 0; public BASE_DIFFUSE_ROUGHNESS = false; + public BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; public BAKED_VERTEX_ANIMATION_TEXTURE = false; @@ -378,26 +471,78 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public static DEFAULT_AO_ON_ANALYTICAL_LIGHTS = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; /** - * Base Color uniform property. + * Base Weight is a multiplier on the diffuse and metal lobes. + * See OpenPBR's specs for base_weight */ - get baseColor(): Color3 { - return this._baseColor.value; - } - set baseColor(color: Color3) { - this._baseColor.value = color; - } - private _baseColor: Property = new Property("baseColor", Color3.White()); + 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 */ - get baseColorTexture(): Nullable { - return this._baseColorTexture.value; - } - set baseColorTexture(texture: Nullable) { - this._baseColorTexture.value = texture; - } - private _baseColorTexture: Sampler = new Sampler("baseColor"); + public baseColorTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseColorTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _baseColorTexture: Sampler = new Sampler("base_color", "baseColor", "ALBEDO"); + + /** + * 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"); + + /** + * 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 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(), "vEmissiveColor", 3); + + private _propertyList: { [name: string]: Property }; + private _uniformsList: { [name: string]: Uniform } = {}; + private _samplersList: { [name: string]: Sampler } = {}; /** * Intensity of the direct lights e.g. the four lights available in your scene. @@ -423,14 +568,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public environmentIntensity: number = 1.0; - /** - * This is a special control allowing the reduction of the specular highlights coming from the - * four lights of the scene. Those highlights may not be needed in full environment lighting. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public specularIntensity: number = 1.0; - /** * Debug Control allowing disabling the bump map on this material. */ @@ -438,27 +575,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public disableBumpMap: boolean = false; - /** - * AKA Diffuse Texture in standard nomenclature. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public albedoTexture: Nullable; - - /** - * OpenPBR Base Weight texture (multiplier to the diffuse and metal lobes). - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public baseWeightTexture: Nullable; - - /** - * OpenPBR Base Diffuse Roughness texture (roughness of the diffuse lobe). - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public baseDiffuseRoughnessTexture: Nullable; - /** * AKA Occlusion Texture in other nomenclature. */ @@ -615,27 +731,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public ambientColor = new Color3(0, 0, 0); - /** - * AKA Diffuse Color in other nomenclature. - */ - @serializeAsColor3("albedo") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public albedoColor = new Color3(1, 1, 1); - - /** - * OpenPBR Base Weight (multiplier to the diffuse and metal lobes). - */ - @serialize("baseWeight") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public baseWeight = 1; - - /** - * OpenPBR Base Diffuse Roughness (roughness of the diffuse lobe). - */ - @serialize("baseDiffuseRoughness") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public baseDiffuseRoughness: Nullable; - /** * AKA Specular Color in other nomenclature. */ @@ -650,13 +745,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public reflectionColor = new Color3(1.0, 1.0, 1.0); - /** - * The color emitted from the material. - */ - @serializeAsColor3("emissive") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public emissiveColor = new Color3(0, 0, 0); - /** * AKA Glossiness in other nomenclature. */ @@ -1000,17 +1088,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _environmentIntensity: number = 1.0; - /** - * This is a special control allowing the reduction of the specular highlights coming from the - * four lights of the scene. Those highlights may not be needed in full environment lighting. - * @internal - */ - public _specularIntensity: 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, this._specularIntensity); + private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, 1.0); /** * Debug Control allowing disabling the bump map on this material. @@ -1018,24 +1099,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _disableBumpMap: boolean = false; - /** - * AKA Diffuse Texture in standard nomenclature. - * @internal - */ - public _albedoTexture: Nullable = null; - - /** - * Base Weight texture (multiplier to the diffuse and metal lobes). - * @internal - */ - public _baseWeightTexture: Nullable = null; - - /** - * Base Diffuse Roughness texture (roughness of the diffuse lobe). - * @internal - */ - public _baseDiffuseRoughnessTexture: Nullable = null; - /** * AKA Occlusion Texture in other nomenclature. * @internal @@ -1172,25 +1235,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _ambientColor = new Color3(0, 0, 0); - /** - * AKA Diffuse Color in other nomenclature. - * @internal - */ - public _albedoColor = new Color3(1, 1, 1); - - /** - * Base Weight (multiplier to the diffuse and metal lobes). - * @internal - */ - public _baseWeight = 1; - - /** - * Base Diffuse Roughness (roughness of the diffuse lobe). - * Can also be used to scale the corresponding texture. - * @internal - */ - public _baseDiffuseRoughness: Nullable = null; - /** * AKA Specular Color in other nomenclature. * @internal @@ -1203,12 +1247,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _reflectionColor = new Color3(1, 1, 1); - /** - * The color applied when light is emitted from a material. - * @internal - */ - public _emissiveColor = new Color3(0, 0, 0); - /** * AKA Glossiness in other nomenclature. * @internal @@ -1526,6 +1564,48 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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; + } + } + + // 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._geometryOpacity; + this._emissionColor; } /** @@ -1572,7 +1652,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return false; } - return this.alpha < 1.0 || this._opacityTexture != null || this._shouldUseAlphaFromAlbedoTexture(); + return this.geometryOpacity < 1.0 || this._opacityTexture != null || this._shouldUseAlphaFromAlbedoTexture(); } /** @@ -1590,21 +1670,14 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { * @returns whether or not the alpha value of the albedo texture should be used for alpha blending. */ protected _shouldUseAlphaFromAlbedoTexture(): boolean { - return this._albedoTexture != null && this._albedoTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE; + 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._albedoTexture != null && this._albedoTexture.hasAlpha) || this._opacityTexture != null; - } - - /** - * @returns the texture used for the alpha test. - */ - public override getAlphaTestTexture(): Nullable { - return this._albedoTexture; + return this._opacityTexture != null; } /** @@ -1740,21 +1813,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._callbackPluginEventHasRenderTargetTextures(this._eventInfo); this._cacheHasRenderTargetTextures = this._eventInfo.hasRenderTargetTextures; if (scene.texturesEnabled) { - if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { - if (!this._albedoTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { - if (!this._baseWeightTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { - if (!this._baseDiffuseRoughnessTexture.isReadyOrNotBlocking()) { - return false; + // 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; + } } } @@ -1924,9 +1989,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public override buildUniformLayout(): void { // Order is important ! const ubo = this._uniformBuffer; - ubo.addUniform("vAlbedoInfos", 2); - ubo.addUniform("vBaseWeightInfos", 2); - ubo.addUniform("vBaseDiffuseRoughnessInfos", 2); ubo.addUniform("vAmbientInfos", 4); ubo.addUniform("vOpacityInfos", 2); ubo.addUniform("vEmissiveInfos", 2); @@ -1934,9 +1996,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.addUniform("vReflectivityInfos", 3); ubo.addUniform("vMicroSurfaceSamplerInfos", 2); ubo.addUniform("vBumpInfos", 3); - ubo.addUniform("albedoMatrix", 16); - ubo.addUniform("baseWeightMatrix", 16); - ubo.addUniform("baseDiffuseRoughnessMatrix", 16); ubo.addUniform("ambientMatrix", 16); ubo.addUniform("opacityMatrix", 16); ubo.addUniform("emissiveMatrix", 16); @@ -1945,14 +2004,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.addUniform("microSurfaceSamplerMatrix", 16); ubo.addUniform("bumpMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); - ubo.addUniform("vAlbedoColor", 4); - ubo.addUniform("baseWeight", 1); - ubo.addUniform("baseDiffuseRoughness", 1); ubo.addUniform("vLightingIntensity", 4); ubo.addUniform("pointSize", 1); ubo.addUniform("vReflectivityColor", 4); - ubo.addUniform("vEmissiveColor", 3); + // ubo.addUniform("vEmissiveColor", 3); ubo.addUniform("vAmbientColor", 3); ubo.addUniform("vDebugMode", 2); @@ -1965,6 +2021,16 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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(); } @@ -2033,19 +2099,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { if (!ubo.useUbo || !this.isFrozen || !ubo.isSync || subMesh._drawWrapper._forceRebindOnNextCall) { // Texture uniforms if (scene.texturesEnabled) { - if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { - ubo.updateFloat2("vAlbedoInfos", this._albedoTexture.coordinatesIndex, this._albedoTexture.level); - BindTextureMatrix(this._albedoTexture, ubo, "albedo"); - } - - if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { - ubo.updateFloat2("vBaseWeightInfos", this._baseWeightTexture.coordinatesIndex, this._baseWeightTexture.level); - BindTextureMatrix(this._baseWeightTexture, ubo, "baseWeight"); - } - - if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { - ubo.updateFloat2("vBaseDiffuseRoughnessInfos", this._baseDiffuseRoughnessTexture.coordinatesIndex, this._baseDiffuseRoughnessTexture.level); - BindTextureMatrix(this._baseDiffuseRoughnessTexture, ubo, "baseDiffuseRoughness"); + // 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._ambientTexture && MaterialFlags.AmbientTextureEnabled) { @@ -2134,18 +2194,29 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.updateColor4("vMetallicReflectanceFactors", this._metallicReflectanceColor, this._metallicF0Factor); } - ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); - - ubo.updateColor4("vAlbedoColor", this._albedoColor, this.alpha); - - ubo.updateFloat("baseWeight", this._baseWeight); - ubo.updateFloat("baseDiffuseRoughness", this._baseDiffuseRoughness || 0.0); + // ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); + + 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 = this._specularIntensity; + this._lightingInfos.w = 1.0; // This is used to be _specularIntensity. ubo.updateVector4("vLightingIntensity", this._lightingInfos); @@ -2159,16 +2230,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // Textures if (scene.texturesEnabled) { - if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { - ubo.setTexture("albedoSampler", this._albedoTexture); - } - - if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { - ubo.setTexture("baseWeightSampler", this._baseWeightTexture); - } - - if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { - ubo.setTexture("baseDiffuseRoughnessSampler", this._baseDiffuseRoughnessTexture); + // 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); + } } if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { @@ -2277,16 +2344,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public override getAnimatables(): IAnimatable[] { const results = super.getAnimatables(); - if (this._albedoTexture && this._albedoTexture.animations && this._albedoTexture.animations.length > 0) { - results.push(this._albedoTexture); - } - - if (this._baseWeightTexture && this._baseWeightTexture.animations && this._baseWeightTexture.animations.length > 0) { - results.push(this._baseWeightTexture); - } - - if (this._baseDiffuseRoughnessTexture && this._baseDiffuseRoughnessTexture.animations && this._baseDiffuseRoughnessTexture.animations.length > 0) { - results.push(this._baseDiffuseRoughnessTexture); + // 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._ambientTexture && this._ambientTexture.animations && this._ambientTexture.animations.length > 0) { @@ -2341,16 +2404,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public override getActiveTextures(): BaseTexture[] { const activeTextures = super.getActiveTextures(); - if (this._albedoTexture) { - activeTextures.push(this._albedoTexture); - } - - if (this._baseWeightTexture) { - activeTextures.push(this._baseWeightTexture); - } - - if (this._baseDiffuseRoughnessTexture) { - activeTextures.push(this._baseDiffuseRoughnessTexture); + // 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._ambientTexture) { @@ -2410,16 +2469,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return true; } - if (this._albedoTexture === texture) { - return true; - } - - if (this._baseWeightTexture === texture) { - return true; - } - - if (this._baseDiffuseRoughnessTexture === 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._ambientTexture === texture) { @@ -2491,9 +2546,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._environmentBRDFTexture.dispose(); } - this._albedoTexture?.dispose(); - this._baseWeightTexture?.dispose(); - this._baseDiffuseRoughnessTexture?.dispose(); + // Loop through samplers and dispose the textures + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + sampler.value?.dispose(); + } + this._ambientTexture?.dispose(); this._opacityTexture?.dispose(); this._reflectionTexture?.dispose(); @@ -2666,19 +2724,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vEyePosition", "vLightsType", "vAmbientColor", - "vAlbedoColor", - "baseWeight", - "baseDiffuseRoughness", "vReflectivityColor", "vMetallicReflectanceFactors", - "vEmissiveColor", "visibility", "vFogInfos", "vFogColor", "pointSize", "vAlbedoInfos", - "vBaseWeightInfos", - "vBaseDiffuseRoughnessInfos", "vAmbientInfos", "vOpacityInfos", "vEmissiveInfos", @@ -2690,8 +2742,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vLightmapInfos", "mBones", "albedoMatrix", - "baseWeightMatrix", - "baseDiffuseRoughnessMatrix", "ambientMatrix", "opacityMatrix", "emissiveMatrix", @@ -2712,10 +2762,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "cameraInfo", ]; + for (const uniformName in Object.keys(this._uniformsList)) { + uniforms.push(uniformName); + } + const samplers = [ - "albedoSampler", - "baseWeightSampler", - "baseDiffuseRoughnessSampler", "reflectivitySampler", "ambientSampler", "emissiveSampler", @@ -2734,6 +2785,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "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"]; @@ -2865,23 +2921,16 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines.LODBASEDMICROSFURACE = true; } - if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { - PrepareDefinesForMergedUV(this._albedoTexture, defines, "ALBEDO"); - defines.GAMMAALBEDO = this._albedoTexture.gammaSpace; - } else { - defines.ALBEDO = false; - } - - if (this._baseWeightTexture && MaterialFlags.BaseWeightTextureEnabled) { - PrepareDefinesForMergedUV(this._baseWeightTexture, defines, "BASE_WEIGHT"); - } else { - defines.BASE_WEIGHT = false; - } - - if (this._baseDiffuseRoughnessTexture && MaterialFlags.BaseDiffuseRoughnessTextureEnabled) { - PrepareDefinesForMergedUV(this._baseDiffuseRoughnessTexture, defines, "BASE_DIFFUSE_ROUGHNESS"); - } else { - defines.BASE_DIFFUSE_ROUGHNESS = false; + // TODO - loop through samplers and prepare defines for each texture + for (const key in this._samplersList) { + const sampler = this._samplersList[key]; + defines[sampler.textureDefine + "DIRECTUV"] = 0; + if (sampler.value) { + PrepareDefinesForMergedUV(sampler.value, defines, sampler.textureDefine); + defines["GAMMA" + sampler.textureDefine] = sampler.value.gammaSpace; + } else { + defines[sampler.textureDefine] = false; + } } if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { @@ -2975,7 +3024,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { PrepareDefinesForMergedUV(this._bumpTexture, defines, "BUMP"); - if (this._useParallax && this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) { + if (this._useParallax && this.baseColorTexture && MaterialFlags.DiffuseTextureEnabled) { defines.PARALLAX = true; defines.PARALLAX_RHS = scene.useRightHandedSystem; defines.PARALLAXOCCLUSION = !!this._useParallaxOcclusion; 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/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index cddb7c45b7a..f3f6fd2f887 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -23,9 +23,6 @@ layout(std140, column_major) uniform; // } uniform Material { - vec2 vAlbedoInfos; - vec2 vBaseWeightInfos; - vec2 vBaseDiffuseRoughnessInfos; vec4 vAmbientInfos; vec2 vOpacityInfos; vec2 vEmissiveInfos; @@ -33,9 +30,7 @@ uniform Material { vec3 vReflectivityInfos; vec2 vMicroSurfaceSamplerInfos; vec3 vBumpInfos; - mat4 albedoMatrix; - mat4 baseWeightMatrix; - mat4 baseDiffuseRoughnessMatrix; + mat4 ambientMatrix; mat4 opacityMatrix; mat4 emissiveMatrix; @@ -44,13 +39,9 @@ uniform Material { mat4 microSurfaceSamplerMatrix; mat4 bumpMatrix; vec2 vTangentSpaceParams; - vec4 vAlbedoColor; - float baseWeight; - float baseDiffuseRoughness; vec4 vLightingIntensity; float pointSize; vec4 vReflectivityColor; - vec3 vEmissiveColor; vec3 vAmbientColor; vec2 vDebugMode; @@ -91,7 +82,18 @@ uniform Material { vec3 vSphericalYZ; vec3 vSphericalZX; - #define ADDITIONAL_UBO_DECLARATION + float baseWeight; + vec4 vBaseColor; + float baseDiffuseRoughness; + vec3 vEmissiveColor; + + vec2 baseWeightInfos; + mat4 baseWeightMatrix; + vec2 baseColorInfos; + mat4 baseColorMatrix; + vec2 baseDiffuseRoughnessInfos; + mat4 baseDiffuseRoughnessMatrix; +#define ADDITIONAL_UBO_DECLARATION }; #include 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..84d657669e4 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -0,0 +1,254 @@ +uniform vec4 vEyePosition; + +uniform vec3 vReflectionColor; +uniform vec4 vBaseColor; +uniform float baseWeight; +uniform float baseDiffuseRoughness; + +// CUSTOM CONTROLS +uniform vec4 vLightingIntensity; + +uniform vec4 vReflectivityColor; +uniform vec4 vMetallicReflectanceFactors; +uniform vec3 vEmissiveColor; + +uniform float visibility; + +uniform vec3 vAmbientColor; + +// Samplers +#ifdef ALBEDO +uniform vec2 baseColorInfos; +#endif + +#ifdef BASE_WEIGHT +uniform vec2 baseWeightInfos; +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS +uniform vec2 baseDiffuseRoughnessInfos; +#endif + +#ifdef AMBIENT +uniform vec4 vAmbientInfos; +#endif + +#ifdef BUMP +uniform vec3 vBumpInfos; +uniform vec2 vTangentSpaceParams; +#endif + +#ifdef OPACITY +uniform vec2 vOpacityInfos; +#endif + +#ifdef EMISSIVE +uniform vec2 vEmissiveInfos; +#endif + +#ifdef LIGHTMAP +uniform vec2 vLightmapInfos; +#endif + +#ifdef REFLECTIVITY +uniform vec3 vReflectivityInfos; +#endif + +#ifdef MICROSURFACEMAP +uniform vec2 vMicroSurfaceSamplerInfos; +#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 + +// Refraction +#if defined(SS_REFRACTION) && defined(SS_USE_LOCAL_REFRACTIONMAP_CUBIC) + uniform vec3 vRefractionPosition; + uniform vec3 vRefractionSize; +#endif + +// Clear Coat +#ifdef CLEARCOAT + uniform vec2 vClearCoatParams; + uniform vec4 vClearCoatRefractionParams; + + #if defined(CLEARCOAT_TEXTURE) || defined(CLEARCOAT_TEXTURE_ROUGHNESS) + uniform vec4 vClearCoatInfos; + #endif + + #ifdef CLEARCOAT_TEXTURE + uniform mat4 clearCoatMatrix; + #endif + + #ifdef CLEARCOAT_TEXTURE_ROUGHNESS + uniform mat4 clearCoatRoughnessMatrix; + #endif + + #ifdef CLEARCOAT_BUMP + uniform vec2 vClearCoatBumpInfos; + uniform vec2 vClearCoatTangentSpaceParams; + uniform mat4 clearCoatBumpMatrix; + #endif + + #ifdef CLEARCOAT_TINT + uniform vec4 vClearCoatTintParams; + uniform float clearCoatColorAtDistance; + + #ifdef CLEARCOAT_TINT_TEXTURE + uniform vec2 vClearCoatTintInfos; + uniform mat4 clearCoatTintMatrix; + #endif + #endif +#endif + +// Iridescence +#ifdef IRIDESCENCE + uniform vec4 vIridescenceParams; + + #if defined(IRIDESCENCE_TEXTURE) || defined(IRIDESCENCE_THICKNESS_TEXTURE) + uniform vec4 vIridescenceInfos; + #endif + + #ifdef IRIDESCENCE_TEXTURE + uniform mat4 iridescenceMatrix; + #endif + + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + uniform mat4 iridescenceThicknessMatrix; + #endif +#endif + +// Anisotropy +#ifdef ANISOTROPIC + uniform vec3 vAnisotropy; + + #ifdef ANISOTROPIC_TEXTURE + uniform vec2 vAnisotropyInfos; + uniform mat4 anisotropyMatrix; + #endif +#endif + +// Sheen +#ifdef SHEEN + uniform vec4 vSheenColor; + #ifdef SHEEN_ROUGHNESS + uniform float vSheenRoughness; + #endif + + #if defined(SHEEN_TEXTURE) || defined(SHEEN_TEXTURE_ROUGHNESS) + uniform vec4 vSheenInfos; + #endif + + #ifdef SHEEN_TEXTURE + uniform mat4 sheenMatrix; + #endif + + #ifdef SHEEN_TEXTURE_ROUGHNESS + uniform mat4 sheenRoughnessMatrix; + #endif +#endif + +// SubSurface +#ifdef SUBSURFACE + #ifdef SS_REFRACTION + uniform vec4 vRefractionMicrosurfaceInfos; + uniform vec4 vRefractionInfos; + uniform mat4 refractionMatrix; + #ifdef REALTIME_FILTERING + uniform vec2 vRefractionFilteringInfo; + #endif + #ifdef SS_DISPERSION + uniform float dispersion; + #endif + #endif + + #ifdef SS_THICKNESSANDMASK_TEXTURE + uniform vec2 vThicknessInfos; + uniform mat4 thicknessMatrix; + #endif + + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + uniform vec2 vRefractionIntensityInfos; + uniform mat4 refractionIntensityMatrix; + #endif + + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + uniform vec2 vTranslucencyIntensityInfos; + uniform mat4 translucencyIntensityMatrix; + #endif + + uniform vec2 vThicknessParam; + uniform vec3 vDiffusionDistance; + uniform vec4 vTintColor; + uniform vec3 vSubSurfaceIntensity; + + uniform vec4 vTranslucencyColor; + + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + uniform vec2 vTranslucencyColorInfos; + uniform mat4 translucencyColorMatrix; + #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..7b767c79805 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -0,0 +1,124 @@ +#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_SAMPLERNAME_,baseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_SAMPLERNAME_,baseDiffuseRoughness) +#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) +#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) +#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) +#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_SAMPLERNAME_,reflectivity) +#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_SAMPLERNAME_,microSurface) +#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_SAMPLERNAME_,metallicReflectance) +#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_SAMPLERNAME_,reflectance) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_SAMPLERNAME_,clearCoat) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) + uniform sampler2D clearCoatRoughnessSampler; + #endif + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_SAMPLERNAME_,clearCoatBump) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_SAMPLERNAME_,clearCoatTint) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_SAMPLERNAME_,iridescence) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_SAMPLERNAME_,iridescenceThickness) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_SAMPLERNAME_,sheen) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) + #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) + uniform sampler2D sheenRoughnessSampler; + #endif +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_SAMPLERNAME_,anisotropy) +#endif + +// 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..b452496e757 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -0,0 +1,206 @@ +uniform mat4 view; +uniform mat4 viewProjection; +uniform vec4 vEyePosition; +#ifdef MULTIVIEW + mat4 viewProjectionR; +#endif + +#ifdef ALBEDO +uniform vec2 baseColorInfos; +uniform mat4 baseColorMatrix; +#endif + +#ifdef BASE_WEIGHT +uniform mat4 baseWeightMatrix; +uniform vec2 baseWeightInfos; +#endif + +uniform float baseDiffuseRoughness; +#ifdef BASE_DIFFUSE_ROUGHNESS +uniform mat4 baseDiffuseRoughnessMatrix; +uniform vec2 baseDiffuseRoughnessInfos; +#endif + +#ifdef AMBIENT +uniform mat4 ambientMatrix; +uniform vec4 vAmbientInfos; +#endif + +#ifdef OPACITY +uniform mat4 opacityMatrix; +uniform vec2 vOpacityInfos; +#endif + +#ifdef EMISSIVE +uniform vec2 vEmissiveInfos; +uniform mat4 emissiveMatrix; +#endif + +#ifdef LIGHTMAP +uniform vec2 vLightmapInfos; +uniform mat4 lightmapMatrix; +#endif + +#ifdef REFLECTIVITY +uniform vec3 vReflectivityInfos; +uniform mat4 reflectivityMatrix; +#endif + +#ifdef METALLIC_REFLECTANCE + uniform vec2 vMetallicReflectanceInfos; + uniform mat4 metallicReflectanceMatrix; +#endif +#ifdef REFLECTANCE + uniform vec2 vReflectanceInfos; + uniform mat4 reflectanceMatrix; +#endif + +#ifdef MICROSURFACEMAP +uniform vec2 vMicroSurfaceSamplerInfos; +uniform mat4 microSurfaceSamplerMatrix; +#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 + +// Clear Coat +#ifdef CLEARCOAT + #if defined(CLEARCOAT_TEXTURE) || defined(CLEARCOAT_TEXTURE_ROUGHNESS) + uniform vec4 vClearCoatInfos; + #endif + + #ifdef CLEARCOAT_TEXTURE + uniform mat4 clearCoatMatrix; + #endif + + #ifdef CLEARCOAT_TEXTURE_ROUGHNESS + uniform mat4 clearCoatRoughnessMatrix; + #endif + + #ifdef CLEARCOAT_BUMP + uniform vec2 vClearCoatBumpInfos; + uniform mat4 clearCoatBumpMatrix; + #endif + + #ifdef CLEARCOAT_TINT_TEXTURE + uniform vec2 vClearCoatTintInfos; + uniform mat4 clearCoatTintMatrix; + #endif +#endif + +// Iridescence +#ifdef IRIDESCENCE + #if defined(IRIDESCENCE_TEXTURE) || defined(IRIDESCENCE_THICKNESS_TEXTURE) + uniform vec4 vIridescenceInfos; + #endif + + #ifdef IRIDESCENCE_TEXTURE + uniform mat4 iridescenceMatrix; + #endif + + #ifdef IRIDESCENCE_THICKNESS_TEXTURE + uniform mat4 iridescenceThicknessMatrix; + #endif +#endif + +// Anisotropy +#ifdef ANISOTROPIC + #ifdef ANISOTROPIC_TEXTURE + uniform vec2 vAnisotropyInfos; + uniform mat4 anisotropyMatrix; + #endif +#endif + +// Sheen +#ifdef SHEEN + #if defined(SHEEN_TEXTURE) || defined(SHEEN_TEXTURE_ROUGHNESS) + uniform vec4 vSheenInfos; + #endif + + #ifdef SHEEN_TEXTURE + uniform mat4 sheenMatrix; + #endif + + #ifdef SHEEN_TEXTURE_ROUGHNESS + uniform mat4 sheenRoughnessMatrix; + #endif +#endif + +// Sub Surface +#ifdef SUBSURFACE + #ifdef SS_REFRACTION + uniform vec4 vRefractionInfos; + uniform mat4 refractionMatrix; + #endif + + #ifdef SS_THICKNESSANDMASK_TEXTURE + uniform vec2 vThicknessInfos; + uniform mat4 thicknessMatrix; + #endif + + #ifdef SS_REFRACTIONINTENSITY_TEXTURE + uniform vec2 vRefractionIntensityInfos; + uniform mat4 refractionIntensityMatrix; + #endif + + #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE + uniform vec2 vTranslucencyIntensityInfos; + uniform mat4 translucencyIntensityMatrix; + #endif + + #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE + uniform vec2 vTranslucencyColorInfos; + uniform mat4 translucencyColorMatrix; + #endif +#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/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index ac621aa07b2..8e901dee728 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -1,4 +1,4 @@ -#define PBR_FRAGMENT_SHADER +#define OPENPBR_FRAGMENT_SHADER #define CUSTOM_FRAGMENT_EXTENSION @@ -27,11 +27,11 @@ precision highp float; #endif // Declaration -#include<__decl__pbrFragment> +#include<__decl__openpbrFragment> #include #include<__decl__lightFragment>[0..maxSimultaneousLights] -#include +#include #include #include #include @@ -89,11 +89,11 @@ void main(void) { albedoOpacityOutParams albedoOpacityOut; #ifdef ALBEDO - vec4 albedoTexture = texture2D(albedoSampler, vAlbedoUV + uvOffset); + vec4 baseColorFromTexture = texture2D(baseColorSampler, vBaseColorUV + uvOffset); #endif #ifdef BASE_WEIGHT - vec4 baseWeightTexture = texture2D(baseWeightSampler, vBaseWeightUV + uvOffset); + vec4 baseWeightFromTexture = texture2D(baseWeightSampler, vBaseWeightUV + uvOffset); #endif #ifdef OPACITY @@ -105,15 +105,15 @@ void main(void) { #endif albedoOpacityOut = albedoOpacityBlock( - vAlbedoColor + vBaseColor #ifdef ALBEDO - , albedoTexture - , vAlbedoInfos + , baseColorFromTexture + , baseColorInfos #endif , baseWeight #ifdef BASE_WEIGHT - , baseWeightTexture - , vBaseWeightInfos + , baseWeightFromTexture + , baseWeightInfos #endif #ifdef OPACITY , opacityMap @@ -202,7 +202,7 @@ void main(void) { #endif #ifdef BASE_DIFFUSE_ROUGHNESS - float baseDiffuseRoughnessTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; + float baseDiffuseRoughnessFromTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; #endif reflectivityOut = reflectivityBlock( @@ -213,8 +213,8 @@ void main(void) { #endif , baseDiffuseRoughness #ifdef BASE_DIFFUSE_ROUGHNESS - , baseDiffuseRoughnessTexture - , vBaseDiffuseRoughnessInfos + , baseDiffuseRoughnessFromTexture + , baseDiffuseRoughnessInfos #endif #ifdef REFLECTIVITY , vReflectivityInfos diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 46a3f34338c..3b4710c6c82 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -1,10 +1,10 @@ -#define PBR_VERTEX_SHADER +#define OPENPBR_VERTEX_SHADER #define CUSTOM_VERTEX_EXTENSION precision highp float; -#include<__decl__pbrVertex> +#include<__decl__openpbrVertex> #define CUSTOM_VERTEX_BEGIN diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index 6eacae512da..6ae5c2455a1 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -1,6 +1,3 @@ -uniform vAlbedoInfos: vec2f; -uniform vBaseWeightInfos: vec2f; -uniform vBaseDiffuseRoughnessInfos: vec2f; uniform vAmbientInfos: vec4f; uniform vOpacityInfos: vec2f; uniform vEmissiveInfos: vec2f; @@ -8,9 +5,7 @@ uniform vLightmapInfos: vec2f; uniform vReflectivityInfos: vec3f; uniform vMicroSurfaceSamplerInfos: vec2f; uniform vBumpInfos: vec3f; -uniform albedoMatrix: mat4x4f; -uniform baseWeightMatrix: mat4x4f; -uniform baseDiffuseRoughnessMatrix: mat4x4f; + uniform ambientMatrix: mat4x4f; uniform opacityMatrix: mat4x4f; uniform emissiveMatrix: mat4x4f; @@ -19,13 +14,9 @@ uniform reflectivityMatrix: mat4x4f; uniform microSurfaceSamplerMatrix: mat4x4f; uniform bumpMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; -uniform vAlbedoColor: vec4f; -uniform baseWeight: f32; -uniform baseDiffuseRoughness: f32; uniform vLightingIntensity: vec4f; uniform pointSize: f32; uniform vReflectivityColor: vec4f; -uniform vEmissiveColor: vec3f; uniform vAmbientColor: vec3f; uniform vDebugMode: vec2f; @@ -66,6 +57,18 @@ uniform vSphericalXY: vec3f; uniform vSphericalYZ: vec3f; uniform vSphericalZX: vec3f; +uniform baseWeight: f32; +uniform vBaseColor: vec4f; +uniform baseDiffuseRoughness: f32; +uniform vEmissiveColor: vec3f; + +uniform baseWeightInfos: vec2f; +uniform baseWeightMatrix: mat4x4f; +uniform baseColorInfos: vec2f; +uniform baseColorMatrix: mat4x4f; +uniform baseDiffuseRoughnessInfos: vec2f; +uniform baseDiffuseRoughnessMatrix: mat4x4f; + #define ADDITIONAL_UBO_DECLARATION 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..363fde264fe --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -0,0 +1,134 @@ +#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight,_SAMPLERNAME_,baseWeight) +#include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness,_SAMPLERNAME_,baseDiffuseRoughness) +#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) +#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) +#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) +#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) +#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_SAMPLERNAME_,reflectivity) +#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_SAMPLERNAME_,microSurface) +#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_SAMPLERNAME_,metallicReflectance) +#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_SAMPLERNAME_,reflectance) +#include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) + +#ifdef CLEARCOAT + #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_SAMPLERNAME_,clearCoat) + #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) + #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) + var clearCoatRoughnessSamplerSampler: sampler; + var clearCoatRoughnessSampler: texture_2d; + #endif + #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_SAMPLERNAME_,clearCoatBump) + #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_SAMPLERNAME_,clearCoatTint) +#endif + +#ifdef IRIDESCENCE + #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_SAMPLERNAME_,iridescence) + #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_SAMPLERNAME_,iridescenceThickness) +#endif + +#ifdef SHEEN + #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_SAMPLERNAME_,sheen) + #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) + #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) + var sheenRoughnessSamplerSampler: sampler; + var sheenRoughnessSampler: texture_2d; + #endif +#endif + +#ifdef ANISOTROPIC + #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_SAMPLERNAME_,anisotropy) +#endif + +// 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 + + +// SUBSURFACE +#ifdef SUBSURFACE + #ifdef SS_REFRACTION + #ifdef SS_REFRACTIONMAP_3D + + var refractionSamplerSampler: sampler; + var refractionSampler: texture_cube; + + #ifdef LODBASEDMICROSFURACE + #else + var refractionLowSamplerSampler: sampler; + var refractionLowSampler: texture_cube; + var refractionHighSamplerSampler: sampler; + var refractionHighSampler: texture_cube; + #endif + #else + + var refractionSamplerSampler: sampler; + var refractionSampler: texture_2d; + + #ifdef LODBASEDMICROSFURACE + #else + var refractionLowSamplerSampler: sampler; + var refractionLowSampler: texture_2d; + var refractionHighSamplerSampler: sampler; + var refractionHighSampler: texture_2d; + #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 + 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/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 83f4b634711..f7e3de2798a 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -1,4 +1,4 @@ -#define PBR_FRAGMENT_SHADER +#define OPENPBR_FRAGMENT_SHADER #define CUSTOM_FRAGMENT_BEGIN @@ -11,11 +11,11 @@ #endif // Declaration -#include +#include #include #include[0..maxSimultaneousLights] -#include +#include #include #include #include @@ -74,11 +74,11 @@ fn main(input: FragmentInputs) -> FragmentOutputs { var albedoOpacityOut: albedoOpacityOutParams; #ifdef ALBEDO - var albedoTexture: vec4f = textureSample(albedoSampler, albedoSamplerSampler, fragmentInputs.vAlbedoUV + uvOffset); + var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, fragmentInputs.vBaseColorUV + uvOffset); #endif #ifdef BASE_WEIGHT - var baseWeightTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, fragmentInputs.vBaseWeightUV + uvOffset); + var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, fragmentInputs.vBaseWeightUV + uvOffset); #endif #ifdef OPACITY @@ -90,15 +90,15 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif albedoOpacityOut = albedoOpacityBlock( - uniforms.vAlbedoColor + uniforms.vBaseColor #ifdef ALBEDO - , albedoTexture - , uniforms.vAlbedoInfos + , baseColorFromTexture + , uniforms.baseColorInfos #endif , uniforms.baseWeight #ifdef BASE_WEIGHT - , baseWeightTexture - , uniforms.vBaseWeightInfos + , baseWeightFromTexture + , uniforms.baseWeightInfos #endif #ifdef OPACITY , opacityMap @@ -164,7 +164,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif #ifdef BASE_DIFFUSE_ROUGHNESS - var baseDiffuseRoughnessTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, fragmentInputs.vBaseDiffuseRoughnessUV + uvOffset).x; + var baseDiffuseRoughnessFromTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, fragmentInputs.vBaseDiffuseRoughnessUV + uvOffset).x; #endif #ifdef METALLICWORKFLOW @@ -198,8 +198,8 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif , uniforms.baseDiffuseRoughness #ifdef BASE_DIFFUSE_ROUGHNESS - , baseDiffuseRoughnessTexture - , uniforms.vBaseDiffuseRoughnessInfos + , baseDiffuseRoughnessFromTexture + , uniforms.baseDiffuseRoughnessInfos #endif #ifdef REFLECTIVITY , uniforms.vReflectivityInfos diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 11eea0f2e3d..493232d3fa5 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -1,6 +1,6 @@ -#define PBR_VERTEX_SHADER +#define OPENPBR_VERTEX_SHADER -#include +#include #define CUSTOM_VERTEX_BEGIN @@ -228,7 +228,7 @@ fn main(input : VertexInputs) -> FragmentInputs { #include[3..7] - #include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,Albedo,_MATRIXNAME_,albedo,_INFONAME_,AlbedoInfos.x) + #include(_DEFINENAME_,ALBEDO,_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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index 0d2dd7ca61a..4e3e537d2f2 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx @@ -117,7 +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 { OpenPBRMaterial } from "core/Materials"; +import type { OpenPBRMaterial } from "core/Materials"; export class PropertyGridTabComponent extends PaneComponent { private _timerIntervalId: number; 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 457913824eb..7eb0ceafa45 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 @@ -47,14 +47,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component - + {material instanceof PBRMaterial && ( + + )} { texture.name = `${babylonMaterial.name} (Diffuse)`; - babylonMaterial.albedoTexture = texture; + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColorTexture = texture; + } else { + babylonMaterial.albedoTexture = texture; + } }) ); } 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 cae66552046..aa64856fe9e 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 @@ -79,17 +79,30 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension { const properties = material.pbrMetallicRoughness; if (properties) { if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); + } else { + babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); + } + babylonMaterial.alpha = properties.baseColorFactor[3]; } else { - babylonMaterial.albedoColor = Color3.White(); + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColor = Color3.White(); + } else { + babylonMaterial.albedoColor = Color3.White(); + } } if (properties.baseColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Base Color)`; - babylonMaterial.albedoTexture = texture; + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColorTexture = texture; + } else { + babylonMaterial.albedoTexture = texture; + } }) ); } 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 aaff3b5b7ec..5e16205e167 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 @@ -55,8 +55,14 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { 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 instanceof OpenPBRMaterial) { + if (!babylonMaterial.baseColorTexture) { + babylonMaterial.baseColor.toLinearSpaceToRef(babylonMaterial.baseColor, useExactSrgbConversions); + } + } else { + if (!babylonMaterial.albedoTexture) { + babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); + } } if (!babylonMaterial.reflectivityTexture) { diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index a772397e428..16e5f3a8509 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -2135,11 +2135,20 @@ export class GLTFLoader implements IGLTFLoader { const promises = new Array>(); if (properties) { - if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.alpha = properties.baseColorFactor[3]; + if (babylonMaterial instanceof OpenPBRMaterial) { + if (properties.baseColorFactor) { + babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); + babylonMaterial.geometryOpacity = properties.baseColorFactor[3]; + } else { + babylonMaterial.baseColor = Color3.White(); + } } else { - babylonMaterial.albedoColor = Color3.White(); + if (properties.baseColorFactor) { + babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); + babylonMaterial.alpha = properties.baseColorFactor[3]; + } else { + babylonMaterial.albedoColor = Color3.White(); + } } babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; @@ -2149,7 +2158,11 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Base Color)`; - babylonMaterial.albedoTexture = texture; + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColorTexture = texture; + } else { + babylonMaterial.albedoTexture = texture; + } }) ); } @@ -2307,7 +2320,11 @@ export class GLTFLoader implements IGLTFLoader { const promises = new Array>(); - babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.emissionColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + } else { + babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + } if (material.doubleSided) { babylonMaterial.backFaceCulling = false; babylonMaterial.twoSidedLighting = true; @@ -2370,6 +2387,8 @@ export class GLTFLoader implements IGLTFLoader { throw new Error(`${context}: Material type not supported`); } + const baseColorTexture = babylonMaterial instanceof OpenPBRMaterial ? babylonMaterial.baseColorTexture : babylonMaterial.albedoTexture; + const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE; switch (alphaMode) { case MaterialAlphaMode.OPAQUE: { @@ -2380,15 +2399,15 @@ export class GLTFLoader implements IGLTFLoader { case MaterialAlphaMode.MASK: { babylonMaterial.transparencyMode = PBRMaterial.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; + if (baseColorTexture) { + baseColorTexture.hasAlpha = true; babylonMaterial.useAlphaFromAlbedoTexture = true; } break; From 555e8df40b7996952479c679ba8a5a6946135972 Mon Sep 17 00:00:00 2001 From: sebavan Date: Thu, 10 Jul 2025 19:52:11 +0200 Subject: [PATCH 13/45] fix build --- packages/dev/buildTools/src/addJSToCompiledFiles.ts | 2 ++ packages/dev/buildTools/src/generateDeclaration.ts | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) 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("=")) { From af04f8e6f73673a191adbb34e13d365a22efb0ff Mon Sep 17 00:00:00 2001 From: Michael Bond Date: Thu, 10 Jul 2025 12:34:52 -0700 Subject: [PATCH 14/45] WIP glTFLoader dynamic material load --- .../Extensions/KHR_materials_anisotropy.ts | 24 ++++-- .../2.0/Extensions/KHR_materials_clearcoat.ts | 70 +++++++++++----- .../KHR_materials_diffuse_transmission.ts | 77 +++++++++++------- .../Extensions/KHR_materials_dispersion.ts | 40 ++++++--- .../KHR_materials_emissive_strength.ts | 17 +++- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 29 +++++-- .../Extensions/KHR_materials_iridescence.ts | 54 +++++++++---- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 81 ++++++++++--------- 8 files changed, 265 insertions(+), 127 deletions(-) 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..a9d2cb7e2eb 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,8 +63,15 @@ 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); @@ -70,23 +80,23 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } 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..034c3b49f8b 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) => { + 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`); + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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..91930aef943 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,8 +69,15 @@ 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadTranslucentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); @@ -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..31bbbf7b404 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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 47785510fe7..0b334915f2c 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -22,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) */ @@ -61,8 +63,15 @@ 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) => { + 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; + } // eslint-disable-next-line github/no-then return await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial).then(() => { this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); @@ -71,7 +80,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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..6c3479fa586 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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..22271fa7961 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); + 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/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 16e5f3a8509..562a3b820eb 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -16,8 +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 { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -87,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; @@ -400,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]}`; @@ -2128,40 +2138,42 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); if (properties) { - if (babylonMaterial instanceof OpenPBRMaterial) { + if (this.parent.useOpenPBR) { + const mat = babylonMaterial as OpenPBRMaterial; if (properties.baseColorFactor) { - babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.geometryOpacity = properties.baseColorFactor[3]; + mat.baseColor = Color3.FromArray(properties.baseColorFactor); + mat.geometryOpacity = properties.baseColorFactor[3]; } else { - babylonMaterial.baseColor = Color3.White(); + mat.baseColor = Color3.White(); } } else { + const mat = babylonMaterial as PBRMaterial; if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.alpha = properties.baseColorFactor[3]; + mat.albedoColor = Color3.FromArray(properties.baseColorFactor); + mat.alpha = properties.baseColorFactor[3]; } else { - babylonMaterial.albedoColor = Color3.White(); + 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)`; - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColorTexture = texture; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; } else { - babylonMaterial.albedoTexture = texture; + (babylonMaterial as PBRMaterial).albedoTexture = texture; } }) ); @@ -2172,13 +2184,13 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Metallic Roughness)`; - babylonMaterial.metallicTexture = texture; + (babylonMaterial as PBRMaterial).metallicTexture = texture; }) ); - babylonMaterial.useMetallnessFromMetallicTextureBlue = true; - babylonMaterial.useRoughnessFromMetallicTextureGreen = true; - babylonMaterial.useRoughnessFromMetallicTextureAlpha = false; + (babylonMaterial as PBRMaterial).useMetallnessFromMetallicTextureBlue = true; + (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureGreen = true; + (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureAlpha = false; } } @@ -2241,12 +2253,7 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; - let babylonMaterial; - if (this.parent.useOpenPBR) { - babylonMaterial = new OpenPBRMaterial(name, this._babylonScene); - } else { - 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; @@ -2254,7 +2261,7 @@ export class GLTFLoader implements IGLTFLoader { babylonMaterial.enableSpecularAntiAliasing = true; babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage; babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage; - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; babylonMaterial.metallic = 1; babylonMaterial.roughness = 1; @@ -2314,16 +2321,16 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.emissionColor = 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.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + (babylonMaterial as PBRMaterial).emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); } if (material.doubleSided) { babylonMaterial.backFaceCulling = false; @@ -2383,21 +2390,21 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const baseColorTexture = babylonMaterial instanceof OpenPBRMaterial ? babylonMaterial.baseColorTexture : babylonMaterial.albedoTexture; + 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 (baseColorTexture) { baseColorTexture.hasAlpha = true; @@ -2405,7 +2412,7 @@ export class GLTFLoader implements IGLTFLoader { break; } case MaterialAlphaMode.BLEND: { - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHABLEND; if (baseColorTexture) { baseColorTexture.hasAlpha = true; babylonMaterial.useAlphaFromAlbedoTexture = true; @@ -2926,7 +2933,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) ); } From a32a8f4438cdae013d0802687f168c5a32870d1f Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 11 Jul 2025 08:42:43 -0700 Subject: [PATCH 15/45] Finish glTFLoader dynamic material load --- .../2.0/Extensions/KHR_materials_sheen.ts | 59 ++++++---- .../2.0/Extensions/KHR_materials_specular.ts | 27 +++-- .../Extensions/KHR_materials_transmission.ts | 104 +++++++++++------- .../2.0/Extensions/KHR_materials_volume.ts | 81 ++++++++++---- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 17 ++- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 27 +++-- .../src/glTF/2.0/glTFLoaderExtension.ts | 3 +- 7 files changed, 217 insertions(+), 101 deletions(-) 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..2a2a734fa02 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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 a55f058dca1..2e18726a4a9 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -24,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) */ @@ -63,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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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 @@ -83,8 +92,8 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material, useOpenPBR: boolean): Promise { + 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_transmission.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts index 5f91a41d555..b404b2d822f 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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_volume.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts index 349cbd67c10..6b70b2453bf 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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 f52207f3e74..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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -21,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 { @@ -45,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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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 5e16205e167..f99204093bb 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -21,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 { @@ -45,23 +47,30 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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 instanceof OpenPBRMaterial) { - if (!babylonMaterial.baseColorTexture) { - babylonMaterial.baseColor.toLinearSpaceToRef(babylonMaterial.baseColor, useExactSrgbConversions); + if (useOpenPBR) { + if (!(babylonMaterial as OpenPBRMaterial).baseColorTexture) { + (babylonMaterial as OpenPBRMaterial).baseColor.toLinearSpaceToRef((babylonMaterial as OpenPBRMaterial).baseColor, useExactSrgbConversions); } } else { - if (!babylonMaterial.albedoTexture) { - babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); + if (!(babylonMaterial as PBRMaterial).albedoTexture) { + (babylonMaterial as PBRMaterial).albedoColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).albedoColor, useExactSrgbConversions); } } 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. From fe839d13e3d25b7c548d7cbe6b1f1da354cf1c14 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 15 Jul 2025 09:00:10 -0700 Subject: [PATCH 16/45] Revert "Finish glTFLoader dynamic material load" This reverts commit c1c7c59d745dd061af842a005998f50bce588fa7. --- .../2.0/Extensions/KHR_materials_sheen.ts | 59 ++++------ .../2.0/Extensions/KHR_materials_specular.ts | 27 ++--- .../Extensions/KHR_materials_transmission.ts | 104 +++++++----------- .../2.0/Extensions/KHR_materials_volume.ts | 81 ++++---------- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 17 +-- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 27 ++--- .../src/glTF/2.0/glTFLoaderExtension.ts | 3 +- 7 files changed, 101 insertions(+), 217 deletions(-) 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 2a2a734fa02..4816792a5e3 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,8 +1,6 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; 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"; @@ -24,8 +22,6 @@ 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) @@ -66,51 +62,46 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial)); // 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, useOpenPBR: boolean): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadSheenPropertiesAsync(context: string, properties: IKHRMaterialsSheen, babylonMaterial: Material): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - let sheenColor = Color3.Black(); - let sheenColorTexture: Nullable = null; - let sheenRoughness = 0.0; - let sheenRoughnessTexture: Nullable = null; - const promises = new Array>(); + babylonMaterial.sheen.isEnabled = true; + babylonMaterial.sheen.intensity = 1; + if (properties.sheenColorFactor != undefined) { - sheenColor = Color3.FromArray(properties.sheenColorFactor); + babylonMaterial.sheen.color = Color3.FromArray(properties.sheenColorFactor); + } else { + babylonMaterial.sheen.color = Color3.Black(); } if (properties.sheenColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/sheenColorTexture`, properties.sheenColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Sheen Color)`; - sheenColorTexture = texture; + babylonMaterial.sheen.texture = texture; }) ); } if (properties.sheenRoughnessFactor !== undefined) { - sheenRoughness = properties.sheenRoughnessFactor; + babylonMaterial.sheen.roughness = properties.sheenRoughnessFactor; + } else { + babylonMaterial.sheen.roughness = 0; } if (properties.sheenRoughnessTexture) { @@ -118,26 +109,16 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/sheenRoughnessTexture`, properties.sheenRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Sheen Roughness)`; - sheenRoughnessTexture = texture; + babylonMaterial.sheen.textureRoughness = texture; }) ); } + babylonMaterial.sheen.albedoScaling = true; + babylonMaterial.sheen.useRoughnessFromMainTexture = false; + // eslint-disable-next-line github/no-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; - }); + return Promise.all(promises).then(() => {}); } } 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 2e18726a4a9..a55f058dca1 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -24,8 +24,6 @@ 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) */ @@ -65,25 +63,18 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial)); // 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 (!useOpenPBR && extension.extensions && extension.extensions.EXT_materials_specular_edge_color) { + if (extension.extensions && extension.extensions.EXT_materials_specular_edge_color && babylonMaterial instanceof PBRMaterial) { const specularEdgeColorExtension = extension.extensions.EXT_materials_specular_edge_color as IEXTMaterialsSpecularEdgeColor; if (specularEdgeColorExtension.specularEdgeColorEnabled) { - (babylonMaterial as PBRMaterial).brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR; - (babylonMaterial as PBRMaterial).brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR; + babylonMaterial.brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR; + babylonMaterial.brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR; } } // eslint-disable-next-line github/no-then @@ -92,8 +83,8 @@ 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, useOpenPBR: boolean): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material): Promise { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } 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 b404b2d822f..5f91a41d555 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,6 +1,5 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -63,8 +62,6 @@ 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. */ @@ -169,7 +166,7 @@ class TransmissionHelper { if (!material) { return false; } - if (material instanceof PBRMaterialClass && (material as any).subSurface.isRefractionEnabled) { + if (material instanceof PBRMaterial && material.subSurface.isRefractionEnabled) { return true; } return false; @@ -223,8 +220,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 PBRMaterialClass) { - (mesh.material as any).subSurface.refractionTexture = this._opaqueRenderTarget; + if (mesh.material instanceof PBRMaterial) { + mesh.material.subSurface.refractionTexture = this._opaqueRenderTarget; } if (opaqueIdx !== -1) { this._opaqueMeshesCache.splice(opaqueIdx, 1); @@ -369,87 +366,60 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); + promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); // 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, - useOpenPBR: boolean - ): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadTransparentPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsTransmission): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { 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; - let transmissionWeight = 0.0; - let transmissionWeightTexture: Nullable = null; + // Albedo colour will tint transmission. + pbrMaterial.subSurface.useAlbedoToTintRefraction = true; - const promises = new Array>(); if (extension.transmissionFactor !== undefined) { - transmissionWeight = extension.transmissionFactor; + 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(); + } } 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 - promises.push( - this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, (texture: BaseTexture) => { - texture.name = `${babylonMaterial.name} (Transmission)`; - transmissionWeightTexture = texture; - }) - ); + 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(); } - - // 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_volume.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts index 6b70b2453bf..349cbd67c10 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,9 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; 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"; @@ -24,8 +22,6 @@ 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 @@ -73,85 +69,50 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); + promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension)); // 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, useOpenPBR: boolean): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadVolumePropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsVolume): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { 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 as PBRMaterial).subSurface.isRefractionEnabled && !(babylonMaterial as PBRMaterial).subSurface.isTranslucencyEnabled) || - !extension.thicknessFactor - ) { + if ((!babylonMaterial.subSurface.isRefractionEnabled && !babylonMaterial.subSurface.isTranslucencyEnabled) || !extension.thicknessFactor) { return Promise.resolve(); } - 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; + // 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; if (extension.attenuationColor !== undefined && extension.attenuationColor.length == 3) { - attenuationColor.copyFromFloats(extension.attenuationColor[0], extension.attenuationColor[1], extension.attenuationColor[2]); + babylonMaterial.subSurface.tintColor.copyFromFloats(extension.attenuationColor[0], extension.attenuationColor[1], extension.attenuationColor[2]); } - thicknessFactor = extension.thicknessFactor; + babylonMaterial.subSurface.minimumThickness = 0.0; + babylonMaterial.subSurface.maximumThickness = extension.thicknessFactor; + babylonMaterial.subSurface.useThicknessAsDepth = true; if (extension.thicknessTexture) { (extension.thicknessTexture as ITextureInfo).nonColorData = true; // eslint-disable-next-line github/no-then - promises.push( - this._loader.loadTextureInfoAsync(`${context}/thicknessTexture`, extension.thicknessTexture, (texture: BaseTexture) => { - texture.name = `${babylonMaterial.name} (Thickness)`; - thicknessTexture = texture; - }) - ); + 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(); } - - // 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 ecb866e40c5..f52207f3e74 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -21,8 +21,6 @@ declare module "../../glTFFileLoader" { } } -let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; - /** @internal */ // eslint-disable-next-line @typescript-eslint/naming-convention export class MSFT_minecraftMesh implements IGLTFLoaderExtension { @@ -47,17 +45,10 @@ export class MSFT_minecraftMesh implements IGLTFLoaderExtension { /** @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): 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 PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { 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 f99204093bb..5e16205e167 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -21,8 +21,6 @@ declare module "../../glTFFileLoader" { } } -let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; - /** @internal */ // eslint-disable-next-line @typescript-eslint/naming-convention export class MSFT_sRGBFactors implements IGLTFLoaderExtension { @@ -47,30 +45,23 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { /** @internal*/ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): 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 PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${extraContext}: Material type not supported`); } const promise = this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial); const useExactSrgbConversions = babylonMaterial.getScene().getEngine().useExactSrgbConversions; - if (useOpenPBR) { - if (!(babylonMaterial as OpenPBRMaterial).baseColorTexture) { - (babylonMaterial as OpenPBRMaterial).baseColor.toLinearSpaceToRef((babylonMaterial as OpenPBRMaterial).baseColor, useExactSrgbConversions); + if (babylonMaterial instanceof OpenPBRMaterial) { + if (!babylonMaterial.baseColorTexture) { + babylonMaterial.baseColor.toLinearSpaceToRef(babylonMaterial.baseColor, useExactSrgbConversions); } } else { - if (!(babylonMaterial as PBRMaterial).albedoTexture) { - (babylonMaterial as PBRMaterial).albedoColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).albedoColor, useExactSrgbConversions); + if (!babylonMaterial.albedoTexture) { + babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); } } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts index 15930ba12e6..72ae55dce23 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoaderExtension.ts @@ -127,10 +127,9 @@ 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, useOpenPBR: boolean): Nullable>; + loadMaterialPropertiesAsync?(context: string, material: IMaterial, babylonMaterial: Material): Nullable>; /** * Define this method to modify the default behavior when loading texture infos. From 68a6cf57d319cdb22d7ce69773a03ec1f5e894d4 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 15 Jul 2025 09:00:24 -0700 Subject: [PATCH 17/45] Revert "WIP glTFLoader dynamic material load" This reverts commit 00d18b18d6aea13545e1afb599fe3a070ee5dd0a. --- .../Extensions/KHR_materials_anisotropy.ts | 24 ++---- .../2.0/Extensions/KHR_materials_clearcoat.ts | 70 +++++----------- .../KHR_materials_diffuse_transmission.ts | 77 +++++++----------- .../Extensions/KHR_materials_dispersion.ts | 40 +++------ .../KHR_materials_emissive_strength.ts | 17 +--- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 29 ++----- .../Extensions/KHR_materials_iridescence.ts | 54 ++++--------- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 81 +++++++++---------- 8 files changed, 127 insertions(+), 265 deletions(-) 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 a9d2cb7e2eb..c425c295da5 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,6 +1,5 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -22,8 +21,6 @@ declare module "../../glTFFileLoader" { } } -let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; - /** * [Specification](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy) */ @@ -63,15 +60,8 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); @@ -80,23 +70,23 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } private async _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsAnisotropy, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - (babylonMaterial as PBRMaterial).anisotropy.isEnabled = true; + babylonMaterial.anisotropy.isEnabled = true; - (babylonMaterial as PBRMaterial).anisotropy.intensity = properties.anisotropyStrength ?? 0; - (babylonMaterial as PBRMaterial).anisotropy.angle = properties.anisotropyRotation ?? 0; + babylonMaterial.anisotropy.intensity = properties.anisotropyStrength ?? 0; + babylonMaterial.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 as PBRMaterial).anisotropy.texture = texture; + babylonMaterial.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 034c3b49f8b..bc394cd1040 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,8 +1,6 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; 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"; @@ -23,8 +21,6 @@ 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) @@ -65,58 +61,46 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } - if (!(babylonMaterial instanceof PBRMaterialClass)) { - throw new Error(`${context}: Material type not supported`); - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial)); await Promise.all(promises); }); } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax - private _loadClearCoatPropertiesAsync(context: string, properties: IKHRMaterialsClearcoat, babylonMaterial: Material, useOpenPBR: boolean = false): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadClearCoatPropertiesAsync(context: string, properties: IKHRMaterialsClearcoat, babylonMaterial: Material): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - let coatRoughness = 0; - let coatWeight = 0; - let coatWeightTexture: Nullable = null; - let coatRoughnessTexture: Nullable = null; - let coatNormalTexture: Nullable = null; - let coatNormalTextureScale = 1; + + babylonMaterial.clearCoat.isEnabled = true; + babylonMaterial.clearCoat.useRoughnessFromMainTexture = false; + babylonMaterial.clearCoat.remapF0OnInterfaceChange = false; if (properties.clearcoatFactor != undefined) { - coatWeight = properties.clearcoatFactor; + babylonMaterial.clearCoat.intensity = properties.clearcoatFactor; } else { - coatWeight = 0; + babylonMaterial.clearCoat.intensity = 0; } if (properties.clearcoatTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatTexture`, properties.clearcoatTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat)`; - coatWeightTexture = texture; + babylonMaterial.clearCoat.texture = texture; }) ); } if (properties.clearcoatRoughnessFactor != undefined) { - coatRoughness = properties.clearcoatRoughnessFactor; + babylonMaterial.clearCoat.roughness = properties.clearcoatRoughnessFactor; } else { - coatRoughness = 0; + babylonMaterial.clearCoat.roughness = 0; } if (properties.clearcoatRoughnessTexture) { @@ -124,7 +108,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatRoughnessTexture`, properties.clearcoatRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat Roughness)`; - coatRoughnessTexture = texture; + babylonMaterial.clearCoat.textureRoughness = texture; }) ); } @@ -134,37 +118,19 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/clearcoatNormalTexture`, properties.clearcoatNormalTexture, (texture) => { texture.name = `${babylonMaterial.name} (ClearCoat Normal)`; - coatNormalTexture = texture; + babylonMaterial.clearCoat.bumpTexture = texture; }) ); babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem; babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem; if (properties.clearcoatNormalTexture.scale != undefined) { - coatNormalTextureScale = properties.clearcoatNormalTexture.scale; + babylonMaterial.clearCoat.bumpTexture!.level = properties.clearcoatNormalTexture.scale; } } // eslint-disable-next-line github/no-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; - } - }); + return Promise.all(promises).then(() => {}); } } 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 91930aef943..5507ebfb1ab 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,7 +1,6 @@ /* eslint-disable github/no-then */ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import type { Material } from "core/Materials/material"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; @@ -24,8 +23,6 @@ declare module "../../glTFFileLoader" { } } -let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; - /** * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1825) * !!! Experimental Extension Subject to Changes !!! @@ -69,15 +66,8 @@ export class KHR_materials_diffuse_transmission implements IGLTFLoaderExtension * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadTranslucentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); @@ -87,71 +77,62 @@ 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 PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - let translucencyWeight = 0.0; - let translucencyWeightTexture: Nullable; - let translucencyColor = Color3.White(); - let translucencyColorTexture: Nullable; + 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; if (extension.diffuseTransmissionFactor !== undefined) { - translucencyWeight = extension.diffuseTransmissionFactor; + pbrMaterial.subSurface.translucencyIntensity = extension.diffuseTransmissionFactor; + } else { + pbrMaterial.subSurface.translucencyIntensity = 0.0; + pbrMaterial.subSurface.isTranslucencyEnabled = false; + return Promise.resolve(); } 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)`; - translucencyWeightTexture = texture; + pbrMaterial.subSurface.translucencyIntensityTexture = texture; }) ); } if (extension.diffuseTransmissionColorFactor !== undefined) { - translucencyColor = Color3.FromArray(extension.diffuseTransmissionColorFactor); + pbrMaterial.subSurface.translucencyColor = Color3.FromArray(extension.diffuseTransmissionColorFactor); + } else { + pbrMaterial.subSurface.translucencyColor = Color3.White(); } if (extension.diffuseTransmissionColorTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/diffuseTransmissionColorTexture`, extension.diffuseTransmissionColorTexture).then((texture: BaseTexture) => { texture.name = `${babylonMaterial.name} (Diffuse Transmission Color)`; - translucencyColorTexture = texture; + pbrMaterial.subSurface.translucencyColorTexture = texture; }) ); } - 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; - }); + return Promise.all(promises).then(() => {}); } } 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 31bbbf7b404..1a99485b358 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,7 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; @@ -22,8 +21,6 @@ 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 @@ -64,44 +61,29 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); + promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension)); // 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, - useOpenPBR: boolean = false - ): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadDispersionPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsDispersion): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - 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; + // 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(); } + 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 0b334915f2c..47785510fe7 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -22,8 +22,6 @@ 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) */ @@ -63,15 +61,8 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } // eslint-disable-next-line github/no-then return await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial).then(() => { this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); @@ -80,7 +71,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { 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 6c3479fa586..ad70f99ba58 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,6 +1,5 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import type { Material } from "core/Materials/material"; import type { IMaterial } from "../glTFLoaderInterfaces"; @@ -22,8 +21,6 @@ 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) */ @@ -68,38 +65,26 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial)); // 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, useOpenPBR: boolean = false): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadIorPropertiesAsync(context: string, properties: IKHRMaterialsIor, babylonMaterial: Material): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - let indexOfRefraction = 1.5; if (properties.ior !== undefined) { - indexOfRefraction = properties.ior; + babylonMaterial.indexOfRefraction = properties.ior; } else { - indexOfRefraction = KHR_materials_ior._DEFAULT_IOR; - } - - if (!useOpenPBR) { - (babylonMaterial as PBRMaterial).indexOfRefraction = indexOfRefraction; + babylonMaterial.indexOfRefraction = KHR_materials_ior._DEFAULT_IOR; } 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 22271fa7961..11168af02da 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,8 +1,6 @@ import type { Nullable } from "core/types"; -import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; 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"; @@ -23,8 +21,6 @@ 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) */ @@ -64,48 +60,36 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { * @internal */ // eslint-disable-next-line no-restricted-syntax - public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { + public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, 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; - } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); // 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, useOpenPBR: boolean = false): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + private _loadIridescencePropertiesAsync(context: string, properties: IKHRMaterialsIridescence, babylonMaterial: Material): Promise { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - let iridescenceWeight = 0.0; - let iridescenceWeightTexture: Nullable = null; - let iridescenceIor = 1.3; - let iridescenceThicknessMinimum = 100; - let iridescenceThicknessMaximum = 400; - let iridescenceThicknessTexture: Nullable = null; - const promises = new Array>(); - iridescenceWeight = properties.iridescenceFactor ?? 0; - iridescenceIor = properties.iridescenceIor ?? (properties as any).iridescenceIOR ?? 1.3; - iridescenceThicknessMinimum = properties.iridescenceThicknessMinimum ?? 100; - iridescenceThicknessMaximum = properties.iridescenceThicknessMaximum ?? 400; + babylonMaterial.iridescence.isEnabled = true; + + 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; if (properties.iridescenceTexture) { promises.push( this._loader.loadTextureInfoAsync(`${context}/iridescenceTexture`, properties.iridescenceTexture, (texture) => { texture.name = `${babylonMaterial.name} (Iridescence)`; - iridescenceWeightTexture = texture; + babylonMaterial.iridescence.texture = texture; }) ); } @@ -114,23 +98,13 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/iridescenceThicknessTexture`, properties.iridescenceThicknessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Iridescence Thickness)`; - iridescenceThicknessTexture = texture; + babylonMaterial.iridescence.thicknessTexture = texture; }) ); } // eslint-disable-next-line github/no-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; - }); + return Promise.all(promises).then(() => {}); } } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 562a3b820eb..16e5f3a8509 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -16,8 +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 type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import { 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"; @@ -87,8 +87,6 @@ import { GetTypedArrayConstructor } from "core/Buffers/bufferUtils"; export { GLTFFileLoader }; -let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; - interface ILoaderProperty extends IProperty { _activeLoaderExtensionFunctions: { [id: string]: boolean; @@ -402,14 +400,6 @@ 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]}`; @@ -2138,42 +2128,40 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); if (properties) { - if (this.parent.useOpenPBR) { - const mat = babylonMaterial as OpenPBRMaterial; + if (babylonMaterial instanceof OpenPBRMaterial) { if (properties.baseColorFactor) { - mat.baseColor = Color3.FromArray(properties.baseColorFactor); - mat.geometryOpacity = properties.baseColorFactor[3]; + babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); + babylonMaterial.geometryOpacity = properties.baseColorFactor[3]; } else { - mat.baseColor = Color3.White(); + babylonMaterial.baseColor = Color3.White(); } } else { - const mat = babylonMaterial as PBRMaterial; if (properties.baseColorFactor) { - mat.albedoColor = Color3.FromArray(properties.baseColorFactor); - mat.alpha = properties.baseColorFactor[3]; + babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); + babylonMaterial.alpha = properties.baseColorFactor[3]; } else { - mat.albedoColor = Color3.White(); + babylonMaterial.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)`; - if (this.parent.useOpenPBR) { - (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseColorTexture = texture; } else { - (babylonMaterial as PBRMaterial).albedoTexture = texture; + babylonMaterial.albedoTexture = texture; } }) ); @@ -2184,13 +2172,13 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Metallic Roughness)`; - (babylonMaterial as PBRMaterial).metallicTexture = texture; + babylonMaterial.metallicTexture = texture; }) ); - (babylonMaterial as PBRMaterial).useMetallnessFromMetallicTextureBlue = true; - (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureGreen = true; - (babylonMaterial as PBRMaterial).useRoughnessFromMetallicTextureAlpha = false; + babylonMaterial.useMetallnessFromMetallicTextureBlue = true; + babylonMaterial.useRoughnessFromMetallicTextureGreen = true; + babylonMaterial.useRoughnessFromMetallicTextureAlpha = false; } } @@ -2253,7 +2241,12 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; - const babylonMaterial = new PBRMaterialClass(name, this._babylonScene); + let babylonMaterial; + if (this.parent.useOpenPBR) { + babylonMaterial = new OpenPBRMaterial(name, this._babylonScene); + } else { + babylonMaterial = new PBRMaterial(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; @@ -2261,7 +2254,7 @@ export class GLTFLoader implements IGLTFLoader { babylonMaterial.enableSpecularAntiAliasing = true; babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage; babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage; - babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; + babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; babylonMaterial.metallic = 1; babylonMaterial.roughness = 1; @@ -2321,16 +2314,16 @@ 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 PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - if (this.parent.useOpenPBR) { - (babylonMaterial as OpenPBRMaterial).emissionColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.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); + babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); } if (material.doubleSided) { babylonMaterial.backFaceCulling = false; @@ -2390,21 +2383,21 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterialClass)) { + if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { throw new Error(`${context}: Material type not supported`); } - const baseColorTexture = this.parent.useOpenPBR ? (babylonMaterial as OpenPBRMaterial).baseColorTexture : (babylonMaterial as PBRMaterial).albedoTexture; + const baseColorTexture = babylonMaterial instanceof OpenPBRMaterial ? babylonMaterial.baseColorTexture : babylonMaterial.albedoTexture; const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE; switch (alphaMode) { case MaterialAlphaMode.OPAQUE: { - babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; + babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; babylonMaterial.alpha = 1.0; // Force alpha to 1.0 for opaque mode. break; } case MaterialAlphaMode.MASK: { - babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHATEST; + babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHATEST; babylonMaterial.alphaCutOff = material.alphaCutoff == undefined ? 0.5 : material.alphaCutoff; if (baseColorTexture) { baseColorTexture.hasAlpha = true; @@ -2412,7 +2405,7 @@ export class GLTFLoader implements IGLTFLoader { break; } case MaterialAlphaMode.BLEND: { - babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHABLEND; + babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND; if (baseColorTexture) { baseColorTexture.hasAlpha = true; babylonMaterial.useAlphaFromAlbedoTexture = true; @@ -2933,7 +2926,7 @@ export class GLTFLoader implements IGLTFLoader { return this._applyExtensions( material, "loadMaterialProperties", - (extension) => extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial, this.parent.useOpenPBR) + (extension) => extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial) ); } From b2bf2c3649a710939dc21ef0125ca638a60ffc53 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 16 Jul 2025 17:26:39 -0700 Subject: [PATCH 18/45] WIP replacing PBR props with OpenPBR props --- .../core/src/Materials/PBR/openPbrMaterial.ts | 585 ++++-------------- .../ShadersInclude/openPbrUboDeclaration.fx | 27 +- .../openpbrBlockFinalColorComposition.fx | 34 + .../openpbrBlockFinalLitComponents.fx | 69 +++ .../ShadersInclude/openpbrBlockReflectance.fx | 36 ++ .../openpbrBlockReflectivity.fx | 135 ++++ .../openpbrFragmentDeclaration.fx | 147 +---- .../openpbrFragmentSamplersDeclaration.fx | 30 +- .../openpbrVertexDeclaration.fx | 19 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 478 +++----------- .../dev/core/src/Shaders/openpbr.vertex.fx | 45 +- .../ShadersInclude/openPbrUboDeclaration.fx | 26 +- .../openpbrBlockFinalColorComposition.fx | 34 + .../openpbrBlockFinalLitComponents.fx | 73 +++ .../ShadersInclude/openpbrBlockReflectance.fx | 36 ++ .../openpbrBlockReflectivity.fx | 137 ++++ .../openpbrFragmentSamplersDeclaration.fx | 73 +-- .../core/src/ShadersWGSL/openpbr.fragment.fx | 459 ++------------ .../core/src/ShadersWGSL/openpbr.vertex.fx | 75 +-- .../pbrMaterialPropertyGridComponent.tsx | 94 +-- .../KHR_materials_pbrSpecularGlossiness.ts | 21 +- .../2.0/Extensions/KHR_materials_specular.ts | 76 ++- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 7 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 29 +- 24 files changed, 970 insertions(+), 1775 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 534ba8992c4..24486482428 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -3,7 +3,7 @@ import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, add import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import { Scene } from "../../scene"; -import { Color3, Color4, TmpColors } from "../../Maths/math.color"; +import { Color3, Color4 } from "../../Maths/math.color"; import { ImageProcessingConfiguration } from "../imageProcessingConfiguration"; import type { BaseTexture } from "../../Materials/Textures/baseTexture"; import { PBRBaseMaterial } from "./pbrBaseMaterial"; @@ -176,7 +176,7 @@ class Sampler { * - openpbr.fragment.fx */ public get samplerInfoName(): string { - return this.samplerPrefix + "Infos"; + return "v" + this.samplerPrefix.charAt(0).toUpperCase() + this.samplerPrefix.slice(1) + "Infos"; } /** * The name of the matrix used for this sampler in the shader. @@ -213,16 +213,8 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public REALTIME_FILTERING = false; public IBL_CDF_FILTERING = false; - public ALBEDO = false; - public GAMMAALBEDO = false; - public ALBEDODIRECTUV = 0; public VERTEXCOLOR = false; - public BASE_WEIGHT = false; - public BASE_WEIGHTDIRECTUV = 0; - public BASE_DIFFUSE_ROUGHNESS = false; - public BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; - public BAKED_VERTEX_ANIMATION_TEXTURE = false; public AMBIENT = false; @@ -238,17 +230,12 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public ALPHABLEND = false; public ALPHAFROMALBEDO = false; public ALPHATESTVALUE = "0.5"; - public SPECULAROVERALPHA = false; - public RADIANCEOVERALPHA = false; - public ALPHAFRESNEL = false; - public LINEARALPHAFRESNEL = false; public PREMULTIPLYALPHA = false; public EMISSIVE = false; public EMISSIVEDIRECTUV = 0; public GAMMAEMISSIVE = false; - public REFLECTIVITY = false; public REFLECTIVITY_GAMMA = false; public REFLECTIVITYDIRECTUV = 0; public SPECULARTERM = false; @@ -256,21 +243,13 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public MICROSURFACEFROMREFLECTIVITYMAP = false; public MICROSURFACEAUTOMATIC = false; public LODBASEDMICROSFURACE = false; - public MICROSURFACEMAP = false; - public MICROSURFACEMAPDIRECTUV = 0; public METALLICWORKFLOW = true; public ROUGHNESSSTOREINMETALMAPALPHA = false; public ROUGHNESSSTOREINMETALMAPGREEN = false; public METALLNESSSTOREINMETALMAPBLUE = false; public AOSTOREINMETALMAPRED = false; - public METALLIC_REFLECTANCE = false; - public METALLIC_REFLECTANCE_GAMMA = false; - public METALLIC_REFLECTANCEDIRECTUV = 0; - public METALLIC_REFLECTANCE_USE_ALPHA_ONLY = false; - public REFLECTANCE = false; - public REFLECTANCE_GAMMA = false; - public REFLECTANCEDIRECTUV = 0; + public SPECULAR_WEIGHT_USE_ALPHA_ONLY = false; public ENVIRONMENTBRDF = false; public ENVIRONMENTBRDF_RGBD = false; @@ -524,6 +503,78 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // 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 */ @@ -543,6 +594,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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. @@ -620,95 +672,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public emissiveTexture: Nullable; /** - * AKA Specular texture in other nomenclature. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public reflectivityTexture: Nullable; - - /** - * Used to switch from specular/glossiness to metallic/roughness workflow. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public metallicTexture: Nullable; - - /** - * Specifies the metallic scalar of the metallic/roughness workflow. - * Can also be used to scale the metalness values of the metallic texture. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public metallic: Nullable; - - /** - * Specifies the roughness scalar of the metallic/roughness workflow. - * Can also be used to scale the roughness values of the metallic texture. + * Specifies that the specular weight is stored in the alpha channel of the specular weight texture. */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public roughness: Nullable; - - /** - * In metallic workflow, specifies an F0 factor to help configuring the material F0. - * By default the indexOfrefraction is used to compute F0; - * - * This is used as a factor against the default reflectance at normal incidence to tweak it. - * - * F0 = defaultF0 * metallicF0Factor * metallicReflectanceColor; - * F90 = metallicReflectanceColor; - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public metallicF0Factor = 1; - - /** - * In metallic workflow, specifies an F0 color. - * By default the F90 is always 1; - * - * Please note that this factor is also used as a factor against the default reflectance at normal incidence. - * - * F0 = defaultF0_from_IOR * metallicF0Factor * metallicReflectanceColor - * F90 = metallicF0Factor; - */ - @serializeAsColor3() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public metallicReflectanceColor = Color3.White(); - - /** - * Specifies that only the A channel from metallicReflectanceTexture should be used. - * If false, both RGB and A channels will be used - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useOnlyMetallicFromMetallicReflectanceTexture = false; - - /** - * Defines to store metallicReflectanceColor in RGB and metallicF0Factor in A - * This is multiplied against the scalar values defined in the material. - * If useOnlyMetallicFromMetallicReflectanceTexture is true, don't use the RGB channels, only A - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public metallicReflectanceTexture: Nullable; - - /** - * Defines to store reflectanceColor in RGB - * This is multiplied against the scalar values defined in the material. - * If both reflectanceTexture and metallicReflectanceTexture textures are provided and useOnlyMetallicFromMetallicReflectanceTexture - * is false, metallicReflectanceTexture takes priority and reflectanceTexture is not used - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public reflectanceTexture: Nullable; - - /** - * Used to enable roughness/glossiness fetch from a separate channel depending on the current mode. - * Gray Scale represents roughness in metallic mode and glossiness in specular mode. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public microSurfaceTexture: Nullable; + public useSpecularWeightFromTextureAlpha = false; /** * Stores surface normal data used to displace a mesh in a texture. @@ -745,13 +713,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public reflectionColor = new Color3(1.0, 1.0, 1.0); - /** - * AKA Glossiness in other nomenclature. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public microSurface = 1.0; - /** * If true, the light map contains occlusion information instead of lighting info. */ @@ -795,28 +756,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public useMicroSurfaceFromReflectivityMapAlpha = false; - /** - * Specifies if the metallic texture contains the roughness information in its alpha channel. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useRoughnessFromMetallicTextureAlpha = true; - - /** - * Specifies if the metallic texture contains the roughness information in its green channel. - * Needs useRoughnessFromMetallicTextureAlpha to be false. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useRoughnessFromMetallicTextureGreen = false; - - /** - * Specifies if the metallic texture contains the metallness information in its blue channel. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useMetallnessFromMetallicTextureBlue = false; - /** * Specifies if the metallic texture contains the ambient occlusion information in its red channel. */ @@ -1137,85 +1076,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _emissiveTexture: Nullable = null; - /** - * AKA Specular texture in other nomenclature. - * @internal - */ - public _reflectivityTexture: Nullable = null; - - /** - * Used to switch from specular/glossiness to metallic/roughness workflow. - * @internal - */ - public _metallicTexture: Nullable = null; - - /** - * Specifies the metallic scalar of the metallic/roughness workflow. - * Can also be used to scale the metalness values of the metallic texture. - * @internal - */ - public _metallic: Nullable = null; - - /** - * Specifies the roughness scalar of the metallic/roughness workflow. - * Can also be used to scale the roughness values of the metallic texture. - * @internal - */ - public _roughness: Nullable = null; - - /** - * In metallic workflow, specifies an F0 factor to help configuring the material F0. - * By default the indexOfrefraction is used to compute F0; - * - * This is used as a factor against the default reflectance at normal incidence to tweak it. - * - * F0 = defaultF0 * metallicF0Factor * metallicReflectanceColor; - * F90 = metallicReflectanceColor; - * @internal - */ - public _metallicF0Factor = 1; - - /** - * In metallic workflow, specifies an F0 color. - * By default the F90 is always 1; - * - * Please note that this factor is also used as a factor against the default reflectance at normal incidence. - * - * F0 = defaultF0_from_IOR * metallicF0Factor * metallicReflectanceColor - * F90 = metallicF0Factor; - * @internal - */ - public _metallicReflectanceColor = Color3.White(); - /** * Specifies that only the A channel from _metallicReflectanceTexture should be used. * If false, both RGB and A channels will be used * @internal */ - public _useOnlyMetallicFromMetallicReflectanceTexture = false; - - /** - * Defines to store metallicReflectanceColor in RGB and metallicF0Factor in A - * This is multiply against the scalar values defined in the material. - * @internal - */ - public _metallicReflectanceTexture: Nullable = null; - - /** - * Defines to store reflectanceColor in RGB - * This is multiplied against the scalar values defined in the material. - * If both _reflectanceTexture and _metallicReflectanceTexture textures are provided and _useOnlyMetallicFromMetallicReflectanceTexture - * is false, _metallicReflectanceTexture takes precedence and _reflectanceTexture is not used - * @internal - */ - public _reflectanceTexture: Nullable = null; - - /** - * Used to enable roughness/glossiness fetch from a separate channel depending on the current mode. - * Gray Scale represents roughness in metallic mode and glossiness in specular mode. - * @internal - */ - public _microSurfaceTexture: Nullable = null; + public _useSpecularWeightFromTextureAlpha = false; /** * Stores surface normal data used to displace a mesh in a texture. @@ -1247,12 +1113,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _reflectionColor = new Color3(1, 1, 1); - /** - * AKA Glossiness in other nomenclature. - * @internal - */ - public _microSurface = 0.9; - /** * Specifies that the material will use the light map as a show map. * @internal @@ -1292,24 +1152,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _useMicroSurfaceFromReflectivityMapAlpha = false; - /** - * Specifies if the metallic texture contains the roughness information in its alpha channel. - * @internal - */ - public _useRoughnessFromMetallicTextureAlpha = true; - - /** - * Specifies if the metallic texture contains the roughness information in its green channel. - * @internal - */ - public _useRoughnessFromMetallicTextureGreen = false; - - /** - * Specifies if the metallic texture contains the metallness information in its blue channel. - * @internal - */ - public _useMetallnessFromMetallicTextureBlue = false; - /** * Specifies if the metallic texture contains the ambient occlusion information in its red channel. * @internal @@ -1597,6 +1439,15 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } + // 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; @@ -1604,6 +1455,14 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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._emissionColor; } @@ -1753,7 +1612,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { if (this._breakShaderLoadedCheck) { return; } - const defines = new OpenPBRMaterialDefines(this._eventInfo.defineNames); + + 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; @@ -1797,7 +1660,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { if (!subMesh.materialDefines) { this._callbackPluginEventGeneric(MaterialPluginEvent.GetDefineNames, this._eventInfo); - subMesh.materialDefines = new OpenPBRMaterialDefines(this._eventInfo.defineNames); + subMesh.materialDefines = new OpenPBRMaterialDefines({ + ...(this._eventInfo.defineNames || {}), + ...(this._samplerDefines || {}), + }); } const defines = subMesh.materialDefines; @@ -1835,7 +1701,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - const reflectionTexture = this._getReflectionTexture2(); + const reflectionTexture = this._getReflectionTexture(); if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { if (!reflectionTexture.isReadyOrNotBlocking()) { return false; @@ -1864,36 +1730,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (MaterialFlags.SpecularTextureEnabled) { - if (this._metallicTexture) { - if (!this._metallicTexture.isReadyOrNotBlocking()) { - return false; - } - } else if (this._reflectivityTexture) { - if (!this._reflectivityTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._metallicReflectanceTexture) { - if (!this._metallicReflectanceTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._reflectanceTexture) { - if (!this._reflectanceTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._microSurfaceTexture) { - if (!this._microSurfaceTexture.isReadyOrNotBlocking()) { - return false; - } - } - } - if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { // Bump texture cannot be not blocking. if (!this._bumpTexture.isReady()) { @@ -1993,32 +1829,21 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.addUniform("vOpacityInfos", 2); ubo.addUniform("vEmissiveInfos", 2); ubo.addUniform("vLightmapInfos", 2); - ubo.addUniform("vReflectivityInfos", 3); - ubo.addUniform("vMicroSurfaceSamplerInfos", 2); ubo.addUniform("vBumpInfos", 3); ubo.addUniform("ambientMatrix", 16); ubo.addUniform("opacityMatrix", 16); ubo.addUniform("emissiveMatrix", 16); ubo.addUniform("lightmapMatrix", 16); - ubo.addUniform("reflectivityMatrix", 16); - ubo.addUniform("microSurfaceSamplerMatrix", 16); ubo.addUniform("bumpMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); ubo.addUniform("vLightingIntensity", 4); ubo.addUniform("pointSize", 1); - ubo.addUniform("vReflectivityColor", 4); // ubo.addUniform("vEmissiveColor", 3); ubo.addUniform("vAmbientColor", 3); ubo.addUniform("vDebugMode", 2); - ubo.addUniform("vMetallicReflectanceFactors", 4); - ubo.addUniform("vMetallicReflectanceInfos", 2); - ubo.addUniform("metallicReflectanceMatrix", 16); - ubo.addUniform("vReflectanceInfos", 2); - ubo.addUniform("reflectanceMatrix", 16); - ubo.addUniform("cameraInfo", 4); PrepareUniformLayoutForIBL(ubo, true, true, true, true, true); @@ -2134,31 +1959,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); } - if (MaterialFlags.SpecularTextureEnabled) { - if (this._metallicTexture) { - ubo.updateFloat3("vReflectivityInfos", this._metallicTexture.coordinatesIndex, this._metallicTexture.level, this._ambientTextureStrength); - BindTextureMatrix(this._metallicTexture, ubo, "reflectivity"); - } else if (this._reflectivityTexture) { - ubo.updateFloat3("vReflectivityInfos", this._reflectivityTexture.coordinatesIndex, this._reflectivityTexture.level, 1.0); - BindTextureMatrix(this._reflectivityTexture, ubo, "reflectivity"); - } - - if (this._metallicReflectanceTexture) { - ubo.updateFloat2("vMetallicReflectanceInfos", this._metallicReflectanceTexture.coordinatesIndex, this._metallicReflectanceTexture.level); - BindTextureMatrix(this._metallicReflectanceTexture, ubo, "metallicReflectance"); - } - - if (this._reflectanceTexture && defines.REFLECTANCE) { - ubo.updateFloat2("vReflectanceInfos", this._reflectanceTexture.coordinatesIndex, this._reflectanceTexture.level); - BindTextureMatrix(this._reflectanceTexture, ubo, "reflectance"); - } - - if (this._microSurfaceTexture) { - ubo.updateFloat2("vMicroSurfaceSamplerInfos", this._microSurfaceTexture.coordinatesIndex, this._microSurfaceTexture.level); - BindTextureMatrix(this._microSurfaceTexture, ubo, "microSurfaceSampler"); - } - } - 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"); @@ -2178,22 +1978,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.updateFloat("pointSize", this.pointSize); } - // Colors - if (defines.METALLICWORKFLOW) { - TmpColors.Color4[0].r = this._metallic === undefined || this._metallic === null ? 1 : this._metallic; - TmpColors.Color4[0].g = this._roughness === undefined || this._roughness === null ? 1 : this._roughness; - const ior = 1.5; - const outsideIOR = 1; // consider air as clear coat and other layers would remap in the shader. - TmpColors.Color4[0].b = ior; - // We are here deriving our default reflectance from a common value for none metallic surface. - // Based of the schlick fresnel approximation model - // for dielectrics. - const f0 = Math.pow((ior - outsideIOR) / (ior + outsideIOR), 2); - TmpColors.Color4[0].a = f0; - ubo.updateDirectColor4("vReflectivityColor", TmpColors.Color4[0]); - ubo.updateColor4("vMetallicReflectanceFactors", this._metallicReflectanceColor, this._metallicF0Factor); - } - // ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); Object.values(this._uniformsList).forEach((uniform) => { @@ -2260,26 +2044,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.setTexture("lightmapSampler", this._lightmapTexture); } - if (MaterialFlags.SpecularTextureEnabled) { - if (this._metallicTexture) { - ubo.setTexture("reflectivitySampler", this._metallicTexture); - } else if (this._reflectivityTexture) { - ubo.setTexture("reflectivitySampler", this._reflectivityTexture); - } - - if (this._metallicReflectanceTexture) { - ubo.setTexture("metallicReflectanceSampler", this._metallicReflectanceTexture); - } - - if (this._reflectanceTexture && defines.REFLECTANCE) { - ubo.setTexture("reflectanceSampler", this._reflectanceTexture); - } - - if (this._microSurfaceTexture) { - ubo.setTexture("microSurfaceSampler", this._microSurfaceTexture); - } - } - if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { ubo.setTexture("bumpSampler", this._bumpTexture); } @@ -2368,12 +2132,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { results.push(this._emissiveTexture); } - if (this._metallicTexture && this._metallicTexture.animations && this._metallicTexture.animations.length > 0) { - results.push(this._metallicTexture); - } else if (this._reflectivityTexture && this._reflectivityTexture.animations && this._reflectivityTexture.animations.length > 0) { - results.push(this._reflectivityTexture); - } - if (this._bumpTexture && this._bumpTexture.animations && this._bumpTexture.animations.length > 0) { results.push(this._bumpTexture); } @@ -2382,18 +2140,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { results.push(this._lightmapTexture); } - if (this._metallicReflectanceTexture && this._metallicReflectanceTexture.animations && this._metallicReflectanceTexture.animations.length > 0) { - results.push(this._metallicReflectanceTexture); - } - - if (this._reflectanceTexture && this._reflectanceTexture.animations && this._reflectanceTexture.animations.length > 0) { - results.push(this._reflectanceTexture); - } - - if (this._microSurfaceTexture && this._microSurfaceTexture.animations && this._microSurfaceTexture.animations.length > 0) { - results.push(this._microSurfaceTexture); - } - return results; } @@ -2428,26 +2174,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { activeTextures.push(this._emissiveTexture); } - if (this._reflectivityTexture) { - activeTextures.push(this._reflectivityTexture); - } - - if (this._metallicTexture) { - activeTextures.push(this._metallicTexture); - } - - if (this._metallicReflectanceTexture) { - activeTextures.push(this._metallicReflectanceTexture); - } - - if (this._reflectanceTexture) { - activeTextures.push(this._reflectanceTexture); - } - - if (this._microSurfaceTexture) { - activeTextures.push(this._microSurfaceTexture); - } - if (this._bumpTexture) { activeTextures.push(this._bumpTexture); } @@ -2493,26 +2219,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return true; } - if (this._reflectivityTexture === texture) { - return true; - } - - if (this._metallicTexture === texture) { - return true; - } - - if (this._metallicReflectanceTexture === texture) { - return true; - } - - if (this._reflectanceTexture === texture) { - return true; - } - - if (this._microSurfaceTexture === texture) { - return true; - } - if (this._bumpTexture === texture) { return true; } @@ -2556,13 +2262,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._opacityTexture?.dispose(); this._reflectionTexture?.dispose(); this._emissiveTexture?.dispose(); - this._metallicTexture?.dispose(); - this._reflectivityTexture?.dispose(); this._bumpTexture?.dispose(); this._lightmapTexture?.dispose(); - this._metallicReflectanceTexture?.dispose(); - this._reflectanceTexture?.dispose(); - this._microSurfaceTexture?.dispose(); } this._renderTargets.dispose(); @@ -2724,7 +2425,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vEyePosition", "vLightsType", "vAmbientColor", - "vReflectivityColor", "vMetallicReflectanceFactors", "visibility", "vFogInfos", @@ -2734,10 +2434,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vAmbientInfos", "vOpacityInfos", "vEmissiveInfos", - "vReflectivityInfos", "vMetallicReflectanceInfos", "vReflectanceInfos", - "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "mBones", @@ -2745,9 +2443,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "ambientMatrix", "opacityMatrix", "emissiveMatrix", - "reflectivityMatrix", "normalMatrix", - "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "metallicReflectanceMatrix", @@ -2773,7 +2469,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "bumpSampler", "lightmapSampler", "opacitySampler", - "microSurfaceSampler", "environmentBrdfSampler", "boneSampler", "metallicReflectanceSampler", @@ -2904,14 +2599,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines["MAINUV" + i] = false; } if (scene.texturesEnabled) { - defines.ALBEDODIRECTUV = 0; - defines.BASE_WEIGHTDIRECTUV = 0; - defines.BASE_DIFFUSE_ROUGHNESSDIRECTUV = 0; defines.AMBIENTDIRECTUV = 0; defines.OPACITYDIRECTUV = 0; defines.EMISSIVEDIRECTUV = 0; defines.REFLECTIVITYDIRECTUV = 0; - defines.MICROSURFACEMAPDIRECTUV = 0; defines.METALLIC_REFLECTANCEDIRECTUV = 0; defines.REFLECTANCEDIRECTUV = 0; defines.BUMPDIRECTUV = 0; @@ -2924,10 +2615,9 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // TODO - loop through samplers and prepare defines for each texture for (const key in this._samplersList) { const sampler = this._samplersList[key]; - defines[sampler.textureDefine + "DIRECTUV"] = 0; if (sampler.value) { PrepareDefinesForMergedUV(sampler.value, defines, sampler.textureDefine); - defines["GAMMA" + sampler.textureDefine] = sampler.value.gammaSpace; + defines[sampler.textureDefine + "_GAMMA"] = sampler.value.gammaSpace; } else { defines[sampler.textureDefine] = false; } @@ -2947,7 +2637,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines.OPACITY = false; } - const reflectionTexture = this._getReflectionTexture2(); + const reflectionTexture = this._getReflectionTexture(); const useSHInFragment: boolean = this._forceIrradianceInFragment || this.realTimeFiltering || @@ -2973,52 +2663,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } if (MaterialFlags.SpecularTextureEnabled) { - if (this._metallicTexture) { - PrepareDefinesForMergedUV(this._metallicTexture, defines, "REFLECTIVITY"); - defines.ROUGHNESSSTOREINMETALMAPALPHA = this._useRoughnessFromMetallicTextureAlpha; - defines.ROUGHNESSSTOREINMETALMAPGREEN = !this._useRoughnessFromMetallicTextureAlpha && this._useRoughnessFromMetallicTextureGreen; - defines.METALLNESSSTOREINMETALMAPBLUE = this._useMetallnessFromMetallicTextureBlue; + if (this._baseMetalRoughTexture) { defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed; - defines.REFLECTIVITY_GAMMA = false; - } else if (this._reflectivityTexture) { - PrepareDefinesForMergedUV(this._reflectivityTexture, defines, "REFLECTIVITY"); - defines.MICROSURFACEFROMREFLECTIVITYMAP = this._useMicroSurfaceFromReflectivityMapAlpha; - defines.MICROSURFACEAUTOMATIC = this._useAutoMicroSurfaceFromReflectivityMap; - defines.REFLECTIVITY_GAMMA = this._reflectivityTexture.gammaSpace; - } else { - defines.REFLECTIVITY = false; - } - - if (this._metallicReflectanceTexture || this._reflectanceTexture) { - defines.METALLIC_REFLECTANCE_USE_ALPHA_ONLY = this._useOnlyMetallicFromMetallicReflectanceTexture; - if (this._metallicReflectanceTexture) { - PrepareDefinesForMergedUV(this._metallicReflectanceTexture, defines, "METALLIC_REFLECTANCE"); - defines.METALLIC_REFLECTANCE_GAMMA = this._metallicReflectanceTexture.gammaSpace; - } else { - defines.METALLIC_REFLECTANCE = false; - } - if ( - this._reflectanceTexture && - (!this._metallicReflectanceTexture || (this._metallicReflectanceTexture && this._useOnlyMetallicFromMetallicReflectanceTexture)) - ) { - PrepareDefinesForMergedUV(this._reflectanceTexture, defines, "REFLECTANCE"); - defines.REFLECTANCE_GAMMA = this._reflectanceTexture.gammaSpace; - } else { - defines.REFLECTANCE = false; - } - } else { - defines.METALLIC_REFLECTANCE = false; - defines.REFLECTANCE = false; } - if (this._microSurfaceTexture) { - PrepareDefinesForMergedUV(this._microSurfaceTexture, defines, "MICROSURFACEMAP"); - } else { - defines.MICROSURFACEMAP = false; - } - } else { - defines.REFLECTIVITY = false; - defines.MICROSURFACEMAP = false; + defines.SPECULAR_WEIGHT_USE_ALPHA_ONLY = this._useSpecularWeightFromTextureAlpha; } if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { @@ -3087,8 +2736,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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); - defines.ALPHAFRESNEL = this._useAlphaFresnel || this._useLinearAlphaFresnel; - defines.LINEARALPHAFRESNEL = this._useLinearAlphaFresnel; } if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) { @@ -3131,18 +2778,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // External config this._callbackPluginEventPrepareDefines(this._eventInfo); } - - /** - * Returns the texture used for reflections. - * @returns - Reflection texture if present. Otherwise, returns the environment texture. - */ - private _getReflectionTexture2(): Nullable { - if (this._reflectionTexture) { - return this._reflectionTexture; - } - - return this.getScene().environmentTexture; - } } RegisterClass("BABYLON.OpenPBRMaterial", OpenPBRMaterial); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index f3f6fd2f887..1d1cf2e74b2 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -27,30 +27,20 @@ uniform Material { vec2 vOpacityInfos; vec2 vEmissiveInfos; vec2 vLightmapInfos; - vec3 vReflectivityInfos; - vec2 vMicroSurfaceSamplerInfos; vec3 vBumpInfos; mat4 ambientMatrix; mat4 opacityMatrix; mat4 emissiveMatrix; mat4 lightmapMatrix; - mat4 reflectivityMatrix; - mat4 microSurfaceSamplerMatrix; mat4 bumpMatrix; vec2 vTangentSpaceParams; vec4 vLightingIntensity; float pointSize; - vec4 vReflectivityColor; vec3 vAmbientColor; vec2 vDebugMode; - vec4 vMetallicReflectanceFactors; - vec2 vMetallicReflectanceInfos; - mat4 metallicReflectanceMatrix; - vec2 vReflectanceInfos; - mat4 reflectanceMatrix; vec4 cameraInfo; vec2 vReflectionInfos; @@ -84,15 +74,24 @@ uniform Material { float baseWeight; vec4 vBaseColor; - float baseDiffuseRoughness; + float vBaseDiffuseRoughness; + vec4 vReflectanceInfo; + vec4 vSpecularColor; vec3 vEmissiveColor; - vec2 baseWeightInfos; + vec2 vBaseWeightInfos; mat4 baseWeightMatrix; - vec2 baseColorInfos; + vec2 vBaseColorInfos; mat4 baseColorMatrix; - vec2 baseDiffuseRoughnessInfos; + vec2 vBaseDiffuseRoughnessInfos; mat4 baseDiffuseRoughnessMatrix; + vec2 vBaseMetalRoughInfos; + mat4 baseMetalRoughMatrix; + vec2 vSpecularWeightInfos; + mat4 specularWeightMatrix; + vec2 vSpecularColorInfos; + mat4 specularColorMatrix; + #define ADDITIONAL_UBO_DECLARATION }; 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..e0a0d3613df --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -0,0 +1,34 @@ +vec4 finalColor = vec4( +#ifndef UNLIT + #ifdef REFLECTION + finalIrradiance + + #endif + #ifdef SPECULARTERM + finalSpecularScaled + + #endif + #ifdef REFLECTION + finalRadianceScaled + + #endif +#endif + finalAmbient + + finalDiffuse, + alpha); + +// _____________________________ LightMappping _____________________________________ +#ifdef LIGHTMAP + #ifndef LIGHTMAPEXCLUDED + #ifdef USELIGHTMAPASSHADOWMAP + finalColor.rgb *= lightmapColor.rgb; + #else + finalColor.rgb += lightmapColor.rgb; + #endif + #endif +#endif + +// _____________________________ EmissiveLight _____________________________________ +finalColor.rgb += finalEmissive; + +#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 index 84d657669e4..fe2d0db835c 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -3,13 +3,11 @@ uniform vec4 vEyePosition; uniform vec3 vReflectionColor; uniform vec4 vBaseColor; uniform float baseWeight; -uniform float baseDiffuseRoughness; +uniform float vBaseDiffuseRoughness; // CUSTOM CONTROLS uniform vec4 vLightingIntensity; -uniform vec4 vReflectivityColor; -uniform vec4 vMetallicReflectanceFactors; uniform vec3 vEmissiveColor; uniform float visibility; @@ -18,15 +16,15 @@ uniform vec3 vAmbientColor; // Samplers #ifdef ALBEDO -uniform vec2 baseColorInfos; +uniform vec2 vBaseColorInfos; #endif #ifdef BASE_WEIGHT -uniform vec2 baseWeightInfos; +uniform vec2 vBaseWeightInfos; #endif #ifdef BASE_DIFFUSE_ROUGHNESS -uniform vec2 baseDiffuseRoughnessInfos; +uniform vec2 vBaseDiffuseRoughnessInfos; #endif #ifdef AMBIENT @@ -50,12 +48,8 @@ uniform vec2 vEmissiveInfos; uniform vec2 vLightmapInfos; #endif -#ifdef REFLECTIVITY -uniform vec3 vReflectivityInfos; -#endif - -#ifdef MICROSURFACEMAP -uniform vec2 vMicroSurfaceSamplerInfos; +#ifdef METALLIC_ROUGHNESS +uniform vec2 vBaseMetalRoughInfos; #endif // Refraction Reflection @@ -82,135 +76,6 @@ uniform mat4 view; #endif #endif -// Refraction -#if defined(SS_REFRACTION) && defined(SS_USE_LOCAL_REFRACTIONMAP_CUBIC) - uniform vec3 vRefractionPosition; - uniform vec3 vRefractionSize; -#endif - -// Clear Coat -#ifdef CLEARCOAT - uniform vec2 vClearCoatParams; - uniform vec4 vClearCoatRefractionParams; - - #if defined(CLEARCOAT_TEXTURE) || defined(CLEARCOAT_TEXTURE_ROUGHNESS) - uniform vec4 vClearCoatInfos; - #endif - - #ifdef CLEARCOAT_TEXTURE - uniform mat4 clearCoatMatrix; - #endif - - #ifdef CLEARCOAT_TEXTURE_ROUGHNESS - uniform mat4 clearCoatRoughnessMatrix; - #endif - - #ifdef CLEARCOAT_BUMP - uniform vec2 vClearCoatBumpInfos; - uniform vec2 vClearCoatTangentSpaceParams; - uniform mat4 clearCoatBumpMatrix; - #endif - - #ifdef CLEARCOAT_TINT - uniform vec4 vClearCoatTintParams; - uniform float clearCoatColorAtDistance; - - #ifdef CLEARCOAT_TINT_TEXTURE - uniform vec2 vClearCoatTintInfos; - uniform mat4 clearCoatTintMatrix; - #endif - #endif -#endif - -// Iridescence -#ifdef IRIDESCENCE - uniform vec4 vIridescenceParams; - - #if defined(IRIDESCENCE_TEXTURE) || defined(IRIDESCENCE_THICKNESS_TEXTURE) - uniform vec4 vIridescenceInfos; - #endif - - #ifdef IRIDESCENCE_TEXTURE - uniform mat4 iridescenceMatrix; - #endif - - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - uniform mat4 iridescenceThicknessMatrix; - #endif -#endif - -// Anisotropy -#ifdef ANISOTROPIC - uniform vec3 vAnisotropy; - - #ifdef ANISOTROPIC_TEXTURE - uniform vec2 vAnisotropyInfos; - uniform mat4 anisotropyMatrix; - #endif -#endif - -// Sheen -#ifdef SHEEN - uniform vec4 vSheenColor; - #ifdef SHEEN_ROUGHNESS - uniform float vSheenRoughness; - #endif - - #if defined(SHEEN_TEXTURE) || defined(SHEEN_TEXTURE_ROUGHNESS) - uniform vec4 vSheenInfos; - #endif - - #ifdef SHEEN_TEXTURE - uniform mat4 sheenMatrix; - #endif - - #ifdef SHEEN_TEXTURE_ROUGHNESS - uniform mat4 sheenRoughnessMatrix; - #endif -#endif - -// SubSurface -#ifdef SUBSURFACE - #ifdef SS_REFRACTION - uniform vec4 vRefractionMicrosurfaceInfos; - uniform vec4 vRefractionInfos; - uniform mat4 refractionMatrix; - #ifdef REALTIME_FILTERING - uniform vec2 vRefractionFilteringInfo; - #endif - #ifdef SS_DISPERSION - uniform float dispersion; - #endif - #endif - - #ifdef SS_THICKNESSANDMASK_TEXTURE - uniform vec2 vThicknessInfos; - uniform mat4 thicknessMatrix; - #endif - - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - uniform vec2 vRefractionIntensityInfos; - uniform mat4 refractionIntensityMatrix; - #endif - - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - uniform vec2 vTranslucencyIntensityInfos; - uniform mat4 translucencyIntensityMatrix; - #endif - - uniform vec2 vThicknessParam; - uniform vec3 vDiffusionDistance; - uniform vec4 vTintColor; - uniform vec3 vSubSurfaceIntensity; - - uniform vec4 vTranslucencyColor; - - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - uniform vec2 vTranslucencyColorInfos; - uniform mat4 translucencyColorMatrix; - #endif -#endif - #ifdef PREPASS #ifdef SS_SCATTERING uniform float scatteringDiffusionProfile; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 7b767c79805..24783ded67f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -5,39 +5,11 @@ #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) -#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_SAMPLERNAME_,reflectivity) -#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_SAMPLERNAME_,microSurface) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_SAMPLERNAME_,baseMetalRough) #include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_SAMPLERNAME_,metallicReflectance) #include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_SAMPLERNAME_,reflectance) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_SAMPLERNAME_,clearCoat) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) - uniform sampler2D clearCoatRoughnessSampler; - #endif - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_SAMPLERNAME_,clearCoatBump) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_SAMPLERNAME_,clearCoatTint) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_SAMPLERNAME_,iridescence) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_SAMPLERNAME_,iridescenceThickness) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_SAMPLERNAME_,sheen) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) - #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) - uniform sampler2D sheenRoughnessSampler; - #endif -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_SAMPLERNAME_,anisotropy) -#endif - // Reflection #ifdef REFLECTION #ifdef REFLECTIONMAP_3D diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx index b452496e757..c304218eb3e 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -6,19 +6,19 @@ uniform vec4 vEyePosition; #endif #ifdef ALBEDO -uniform vec2 baseColorInfos; +uniform vec2 vBaseColorInfos; uniform mat4 baseColorMatrix; #endif #ifdef BASE_WEIGHT uniform mat4 baseWeightMatrix; -uniform vec2 baseWeightInfos; +uniform vec2 vBaseWeightInfos; #endif -uniform float baseDiffuseRoughness; +uniform float vBaseDiffuseRoughness; #ifdef BASE_DIFFUSE_ROUGHNESS uniform mat4 baseDiffuseRoughnessMatrix; -uniform vec2 baseDiffuseRoughnessInfos; +uniform vec2 vBaseDiffuseRoughnessInfos; #endif #ifdef AMBIENT @@ -41,9 +41,9 @@ uniform vec2 vLightmapInfos; uniform mat4 lightmapMatrix; #endif -#ifdef REFLECTIVITY -uniform vec3 vReflectivityInfos; -uniform mat4 reflectivityMatrix; +#ifdef METALLIC_ROUGHNESS +uniform vec2 vBaseMetalRoughInfos; +uniform mat4 baseMetalRoughMatrix; #endif #ifdef METALLIC_REFLECTANCE @@ -55,11 +55,6 @@ uniform mat4 reflectivityMatrix; uniform mat4 reflectanceMatrix; #endif -#ifdef MICROSURFACEMAP -uniform vec2 vMicroSurfaceSamplerInfos; -uniform mat4 microSurfaceSamplerMatrix; -#endif - #ifdef BUMP uniform vec3 vBumpInfos; uniform mat4 bumpMatrix; diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 8e901dee728..18f8c4fd57d 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -2,7 +2,7 @@ #define CUSTOM_FRAGMENT_EXTENSION -#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) #extension GL_OES_standard_derivatives : enable #endif @@ -61,15 +61,10 @@ precision highp float; #define CUSTOM_FRAGMENT_DEFINITIONS #include -#include +#include #include #include -#include #include -#include -#include -#include -#include // _____________________________ MAIN FUNCTION ____________________________ void main(void) { @@ -108,12 +103,12 @@ void main(void) { vBaseColor #ifdef ALBEDO , baseColorFromTexture - , baseColorInfos + , vBaseColorInfos #endif , baseWeight #ifdef BASE_WEIGHT , baseWeightFromTexture - , baseWeightInfos + , vBaseWeightInfos #endif #ifdef OPACITY , opacityMap @@ -138,6 +133,19 @@ void main(void) { #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; @@ -158,129 +166,76 @@ void main(void) { vec3 diffuseBase = vec3(1., 1., 1.); #else // !UNLIT - // _____________________________ Reflectivity _______________________________ - vec3 baseColor = surfaceAlbedo; - + // _____________________________ Reflectivity (Rename this to IBL) _______________________________ + reflectivityOutParams reflectivityOut; -#if defined(REFLECTIVITY) - vec4 surfaceMetallicOrReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset); - vec4 baseReflectivity = surfaceMetallicOrReflectivityColorMap; - #ifndef METALLICWORKFLOW - #ifdef REFLECTIVITY_GAMMA - surfaceMetallicOrReflectivityColorMap = toLinearSpace(surfaceMetallicOrReflectivityColorMap); - #endif - surfaceMetallicOrReflectivityColorMap.rgb *= vReflectivityInfos.y; - #endif +#ifdef METALLIC_ROUGHNESS + vec4 metallicRoughnessFromTexture = texture2D(baseMetalRoughSampler, vBaseMetalRoughUV + uvOffset); #endif -#if defined(MICROSURFACEMAP) - vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y; +#ifdef BASE_DIFFUSE_ROUGHNESS + float baseDiffuseRoughnessFromTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; #endif -#ifdef METALLICWORKFLOW - vec4 metallicReflectanceFactors = vMetallicReflectanceFactors; - #ifdef REFLECTANCE - vec4 reflectanceFactorsMap = texture2D(reflectanceSampler, vReflectanceUV + uvOffset); - #ifdef REFLECTANCE_GAMMA - reflectanceFactorsMap = toLinearSpace(reflectanceFactorsMap); - #endif - - metallicReflectanceFactors.rgb *= reflectanceFactorsMap.rgb; +vec4 specularColor = vSpecularColor; +#ifdef SPECULAR_COLOR + vec4 specularColorFromTexture = texture2D(specularColorSampler, vSpecularColorUV + uvOffset); + #ifdef SPECULAR_COLOR_GAMMA + specularColorFromTexture = toLinearSpace(specularColorFromTexture); #endif - #ifdef METALLIC_REFLECTANCE - vec4 metallicReflectanceFactorsMap = texture2D(metallicReflectanceSampler, vMetallicReflectanceUV + uvOffset); - #ifdef METALLIC_REFLECTANCE_GAMMA - metallicReflectanceFactorsMap = toLinearSpace(metallicReflectanceFactorsMap); - #endif - #ifndef METALLIC_REFLECTANCE_USE_ALPHA_ONLY - metallicReflectanceFactors.rgb *= metallicReflectanceFactorsMap.rgb; - #endif - metallicReflectanceFactors.a *= metallicReflectanceFactorsMap.a; - #endif + specularColor.rgb *= specularColorFromTexture.rgb; #endif +#ifdef SPECULAR_WEIGHT + vec4 specularWeightFromTexture = texture2D(specularWeightSampler, vSpecularWeightUV + uvOffset); + #ifdef SPECULAR_WEIGHT_GAMMA + specularWeightFromTexture = toLinearSpace(specularWeightFromTexture); + #endif -#ifdef BASE_DIFFUSE_ROUGHNESS - float baseDiffuseRoughnessFromTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; + // 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( - vReflectivityColor - #ifdef METALLICWORKFLOW + vReflectanceInfo , surfaceAlbedo - , metallicReflectanceFactors - #endif - , baseDiffuseRoughness + , specularColor + , vBaseDiffuseRoughness #ifdef BASE_DIFFUSE_ROUGHNESS , baseDiffuseRoughnessFromTexture - , baseDiffuseRoughnessInfos + , vBaseDiffuseRoughnessInfos #endif - #ifdef REFLECTIVITY - , vReflectivityInfos - , surfaceMetallicOrReflectivityColorMap + #ifdef METALLIC_ROUGHNESS + , vec3(vBaseMetalRoughInfos, 1.0f) + , metallicRoughnessFromTexture #endif - #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) , aoOut.ambientOcclusionColor #endif - #ifdef MICROSURFACEMAP - , microSurfaceTexel - #endif #ifdef DETAIL , detailColor , vDetailInfos #endif ); - float microSurface = reflectivityOut.microSurface; float roughness = reflectivityOut.roughness; float diffuseRoughness = reflectivityOut.diffuseRoughness; - #ifdef METALLICWORKFLOW - surfaceAlbedo = reflectivityOut.surfaceAlbedo; - #endif - #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + // surfaceAlbedo = reflectivityOut.surfaceAlbedo; + + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; #endif - // _____________________________ Alpha Fresnel ___________________________________ - #ifdef ALPHAFRESNEL - #if defined(ALPHATEST) || defined(ALPHABLEND) - alphaFresnelOutParams alphaFresnelOut; - - alphaFresnelOut = alphaFresnelBlock( - normalW, - viewDirectionW, - alpha, - microSurface - ); - - alpha = alphaFresnelOut.alpha; - #endif - #endif - // _____________________________ Compute Geometry info _________________________________ #include - // _____________________________ Anisotropy _______________________________________ - #ifdef ANISOTROPIC - anisotropicOutParams anisotropicOut; - - #ifdef ANISOTROPIC_TEXTURE - vec3 anisotropyMapData = texture2D(anisotropySampler, vAnisotropyUV + uvOffset).rgb * vAnisotropyInfos.y; - #endif - - anisotropicOut = anisotropicBlock( - vAnisotropy, - roughness, - #ifdef ANISOTROPIC_TEXTURE - anisotropyMapData, - #endif - TBN, - normalW, - viewDirectionW - ); - #endif // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION @@ -328,336 +283,41 @@ void main(void) { #endif , viewDirectionW , diffuseRoughness - , baseColor + , surfaceAlbedo ); #else #define CUSTOM_REFLECTION #endif #endif - // ___________________ Compute Reflectance aka R0 F0 info _________________________ - #include - - // ________________________________ Sheen ______________________________ - #ifdef SHEEN - sheenOutParams sheenOut; - - #ifdef SHEEN_TEXTURE - vec4 sheenMapData = texture2D(sheenSampler, vSheenUV + uvOffset); - #endif - #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) - vec4 sheenMapRoughnessData = texture2D(sheenRoughnessSampler, vSheenRoughnessUV + uvOffset) * vSheenInfos.w; - #endif - - sheenOut = sheenBlock( - vSheenColor - #ifdef SHEEN_ROUGHNESS - , vSheenRoughness - #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) - , sheenMapRoughnessData - #endif - #endif - , roughness - #ifdef SHEEN_TEXTURE - , sheenMapData - , vSheenInfos.y - #endif - , reflectanceF0 - #ifdef SHEEN_LINKWITHALBEDO - , baseColor - , surfaceAlbedo - #endif - #ifdef ENVIRONMENTBRDF - , NdotV - , environmentBrdf - #endif - #if defined(REFLECTION) && defined(ENVIRONMENTBRDF) - , AARoughnessFactors - , vReflectionMicrosurfaceInfos - , vReflectionInfos - , vReflectionColor - , vLightingIntensity - , reflectionSampler - , reflectionOut.reflectionCoords - , NdotVUnclamped - #ifndef LODBASEDMICROSFURACE - , reflectionSamplerLow - , reflectionSamplerHigh - #endif - #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo - #endif - #if !defined(REFLECTIONMAP_SKYBOX) && defined(RADIANCEOCCLUSION) - , seo - #endif - #if !defined(REFLECTIONMAP_SKYBOX) && defined(HORIZONOCCLUSION) && defined(BUMP) && defined(REFLECTIONMAP_3D) - , eho - #endif - #endif - ); - - #ifdef SHEEN_LINKWITHALBEDO - surfaceAlbedo = sheenOut.surfaceAlbedo; - #endif - #endif - - // _____________ Shared Iridescence and Clear Coat data _________________ - #ifdef CLEARCOAT - #ifdef CLEARCOAT_TEXTURE - vec2 clearCoatMapData = texture2D(clearCoatSampler, vClearCoatUV + uvOffset).rg * vClearCoatInfos.y; - #endif - #endif - - // _____________________________ Iridescence ____________________________ - #ifdef IRIDESCENCE - iridescenceOutParams iridescenceOut; - - #ifdef IRIDESCENCE_TEXTURE - vec2 iridescenceMapData = texture2D(iridescenceSampler, vIridescenceUV + uvOffset).rg * vIridescenceInfos.y; - #endif - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - vec2 iridescenceThicknessMapData = texture2D(iridescenceThicknessSampler, vIridescenceThicknessUV + uvOffset).rg * vIridescenceInfos.w; - #endif - - iridescenceOut = iridescenceBlock( - vIridescenceParams - , NdotV - , specularEnvironmentR0 - #ifdef IRIDESCENCE_TEXTURE - , iridescenceMapData - #endif - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - , iridescenceThicknessMapData - #endif - #ifdef CLEARCOAT - , NdotVUnclamped - , vClearCoatParams - #ifdef CLEARCOAT_TEXTURE - , clearCoatMapData - #endif - #endif - ); - - float iridescenceIntensity = iridescenceOut.iridescenceIntensity; - specularEnvironmentR0 = iridescenceOut.specularEnvironmentR0; - #endif - - // _____________________________ Clear Coat ____________________________ - clearcoatOutParams clearcoatOut; - - #ifdef CLEARCOAT - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) - vec4 clearCoatMapRoughnessData = texture2D(clearCoatRoughnessSampler, vClearCoatRoughnessUV + uvOffset) * vClearCoatInfos.w; - #endif - - #if defined(CLEARCOAT_TINT) && defined(CLEARCOAT_TINT_TEXTURE) - vec4 clearCoatTintMapData = texture2D(clearCoatTintSampler, vClearCoatTintUV + uvOffset); - #endif - - #ifdef CLEARCOAT_BUMP - vec4 clearCoatBumpMapData = texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset); - #endif - - clearcoatOut = clearcoatBlock( - vPositionW - , geometricNormalW - , viewDirectionW - , vClearCoatParams - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) - , clearCoatMapRoughnessData - #endif - , specularEnvironmentR0 - #ifdef CLEARCOAT_TEXTURE - , clearCoatMapData - #endif - #ifdef CLEARCOAT_TINT - , vClearCoatTintParams - , clearCoatColorAtDistance - , vClearCoatRefractionParams - #ifdef CLEARCOAT_TINT_TEXTURE - , clearCoatTintMapData - #endif - #endif - #ifdef CLEARCOAT_BUMP - , vClearCoatBumpInfos - , clearCoatBumpMapData - , vClearCoatBumpUV - #if defined(TANGENT) && defined(NORMAL) - , vTBN - #else - , vClearCoatTangentSpaceParams - #endif - #ifdef OBJECTSPACE_NORMALMAP - , normalMatrix - #endif - #endif - #if defined(FORCENORMALFORWARD) && defined(NORMAL) - , faceNormal - #endif - #ifdef REFLECTION - , vReflectionMicrosurfaceInfos - , vReflectionInfos - , vReflectionColor - , vLightingIntensity - , reflectionSampler - #ifndef LODBASEDMICROSFURACE - , reflectionSamplerLow - , reflectionSamplerHigh - #endif - #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo - #endif - #endif - #if defined(CLEARCOAT_BUMP) || defined(TWOSIDEDLIGHTING) - , (gl_FrontFacing ? 1. : -1.) - #endif - ); - #else - clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0; - #endif - // _________________________ Specular Environment Reflectance __________________________ - #include - - // ___________________________________ SubSurface ______________________________________ - subSurfaceOutParams subSurfaceOut; - - #ifdef SUBSURFACE - #ifdef SS_THICKNESSANDMASK_TEXTURE - vec4 thicknessMap = texture2D(thicknessSampler, vThicknessUV + uvOffset); - #endif - - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - vec4 refractionIntensityMap = texture2D(refractionIntensitySampler, vRefractionIntensityUV + uvOffset); - #endif - - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - vec4 translucencyIntensityMap = texture2D(translucencyIntensitySampler, vTranslucencyIntensityUV + uvOffset); - #endif - - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - vec4 translucencyColorMap = texture2D(translucencyColorSampler, vTranslucencyColorUV + uvOffset); - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE_GAMMA - translucencyColorMap = toLinearSpace(translucencyColorMap); - #endif - #endif - - #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION - vec3 vSpecularEnvironmentReflectance = vec3(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b))); - #endif - - subSurfaceOut = subSurfaceBlock( - vSubSurfaceIntensity - , vThicknessParam - , vTintColor - , normalW - #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION - , vSpecularEnvironmentReflectance - #else - , baseSpecularEnvironmentReflectance - #endif - #ifdef SS_THICKNESSANDMASK_TEXTURE - , thicknessMap - #endif - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - , refractionIntensityMap - #endif - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - , translucencyIntensityMap - #endif - #ifdef REFLECTION - #ifdef SS_TRANSLUCENCY - , reflectionMatrix - #ifdef USESPHERICALFROMREFLECTIONMAP - #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) - , reflectionOut.irradianceVector - #endif - #if defined(REALTIME_FILTERING) - , reflectionSampler - , vReflectionFilteringInfo - #ifdef IBL_CDF_FILTERING - , icdfSampler - #endif - #endif - #endif - #ifdef USEIRRADIANCEMAP - , irradianceSampler - #endif - #endif - #endif - #if defined(SS_REFRACTION) || defined(SS_TRANSLUCENCY) - , surfaceAlbedo - #endif - #ifdef SS_REFRACTION - , vPositionW - , viewDirectionW - , view - , vRefractionInfos - , refractionMatrix - , vRefractionMicrosurfaceInfos - , vLightingIntensity - #ifdef SS_LINKREFRACTIONTOTRANSPARENCY - , alpha - #endif - #ifdef SS_LODINREFRACTIONALPHA - , NdotVUnclamped - #endif - #ifdef SS_LINEARSPECULARREFRACTION - , roughness - #endif - , alphaG - , refractionSampler - #ifndef LODBASEDMICROSFURACE - , refractionSamplerLow - , refractionSamplerHigh - #endif - #ifdef ANISOTROPIC - , anisotropicOut - #endif - #ifdef REALTIME_FILTERING - , vRefractionFilteringInfo - #endif - #ifdef SS_USE_LOCAL_REFRACTIONMAP_CUBIC - , vRefractionPosition - , vRefractionSize - #endif - #ifdef SS_DISPERSION - , dispersion - #endif - #endif - #ifdef SS_TRANSLUCENCY - , vDiffusionDistance - , vTranslucencyColor - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - , translucencyColorMap - #endif - #endif - ); - - #ifdef SS_REFRACTION - surfaceAlbedo = subSurfaceOut.surfaceAlbedo; - #ifdef SS_LINKREFRACTIONTOTRANSPARENCY - alpha = subSurfaceOut.alpha; - #endif - #endif - #else - subSurfaceOut.specularEnvironmentReflectance = colorSpecularEnvironmentReflectance; - #endif - + float reflectanceF0 = reflectivityOut.reflectanceF0; + vec3 specularEnvironmentR0 = reflectivityOut.colorReflectanceF0; + vec3 specularEnvironmentR90 = reflectivityOut.colorReflectanceF90; + #include + // _____________________________ Direct Lighting Info __________________________________ #include - #include[0..maxSimultaneousLights] + // 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 + #include #endif // !UNLIT #include #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - #include + #include #include #include(color, finalColor) diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 3b4710c6c82..3bf844c7304 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -41,10 +41,9 @@ attribute vec4 color; #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) -#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity) -#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler) -#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance) -#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) @@ -165,7 +164,7 @@ void main(void) { #endif float NdotV = max(dot(vNormalW, viewDirectionW), 0.0); - vec3 roughNormal = mix(vNormalW, viewDirectionW, (0.5 * (1.0 - NdotV)) * baseDiffuseRoughness); + 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; @@ -221,42 +220,12 @@ void main(void) { #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) - #include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_MATRIXNAME_,reflectivity,_INFONAME_,ReflectivityInfos.x) - #include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_MATRIXNAME_,microSurfaceSampler,_INFONAME_,MicroSurfaceSamplerInfos.x) - #include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_MATRIXNAME_,metallicReflectance,_INFONAME_,MetallicReflectanceInfos.x) - #include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_MATRIXNAME_,reflectance,_INFONAME_,ReflectanceInfos.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_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_MATRIXNAME_,clearCoat,_INFONAME_,ClearCoatInfos.x) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness,_MATRIXNAME_,clearCoatRoughness,_INFONAME_,ClearCoatInfos.z) - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_MATRIXNAME_,clearCoatBump,_INFONAME_,ClearCoatBumpInfos.x) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_MATRIXNAME_,clearCoatTint,_INFONAME_,ClearCoatTintInfos.x) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_MATRIXNAME_,iridescence,_INFONAME_,IridescenceInfos.x) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_MATRIXNAME_,iridescenceThickness,_INFONAME_,IridescenceInfos.z) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_MATRIXNAME_,sheen,_INFONAME_,SheenInfos.x) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness,_MATRIXNAME_,sheenRoughness,_INFONAME_,SheenInfos.z) - -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_MATRIXNAME_,anisotropy,_INFONAME_,AnisotropyInfos.x) -#endif - -#ifdef SUBSURFACE - #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness,_MATRIXNAME_,thickness,_INFONAME_,ThicknessInfos.x) - #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_MATRIXNAME_,refractionIntensity,_INFONAME_,RefractionIntensityInfos.x) - #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_MATRIXNAME_,translucencyIntensity,_INFONAME_,TranslucencyIntensityInfos.x) - #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_MATRIXNAME_,translucencyColor,_INFONAME_,TranslucencyColorInfos.x) -#endif - // TBN #include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index 6ae5c2455a1..be6feacd61c 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -2,30 +2,20 @@ uniform vAmbientInfos: vec4f; uniform vOpacityInfos: vec2f; uniform vEmissiveInfos: vec2f; uniform vLightmapInfos: vec2f; -uniform vReflectivityInfos: vec3f; -uniform vMicroSurfaceSamplerInfos: vec2f; uniform vBumpInfos: vec3f; uniform ambientMatrix: mat4x4f; uniform opacityMatrix: mat4x4f; uniform emissiveMatrix: mat4x4f; uniform lightmapMatrix: mat4x4f; -uniform reflectivityMatrix: mat4x4f; -uniform microSurfaceSamplerMatrix: mat4x4f; uniform bumpMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; uniform vLightingIntensity: vec4f; uniform pointSize: f32; -uniform vReflectivityColor: vec4f; uniform vAmbientColor: vec3f; uniform vDebugMode: vec2f; -uniform vMetallicReflectanceFactors: vec4f; -uniform vMetallicReflectanceInfos: vec2f; -uniform metallicReflectanceMatrix: mat4x4f; -uniform vReflectanceInfos: vec2f; -uniform reflectanceMatrix: mat4x4f; uniform cameraInfo: vec4f; uniform vReflectionInfos: vec2f; @@ -59,15 +49,23 @@ uniform vSphericalZX: vec3f; uniform baseWeight: f32; uniform vBaseColor: vec4f; -uniform baseDiffuseRoughness: f32; +uniform vBaseDiffuseRoughness: f32; +uniform vReflectanceInfo: vec4f; +uniform vSpecularColor: vec4f; uniform vEmissiveColor: vec3f; -uniform baseWeightInfos: vec2f; +uniform vBaseWeightInfos: vec2f; uniform baseWeightMatrix: mat4x4f; -uniform baseColorInfos: vec2f; +uniform vBaseColorInfos: vec2f; uniform baseColorMatrix: mat4x4f; -uniform baseDiffuseRoughnessInfos: vec2f; +uniform vBaseDiffuseRoughnessInfos: vec2f; uniform baseDiffuseRoughnessMatrix: mat4x4f; +uniform vBaseMetalRoughInfos: vec2f; +uniform baseMetalRoughMatrix: mat4x4f; +uniform vSpecularWeightInfos: vec2f; +uniform specularWeightMatrix: mat4x4f; +uniform vSpecularColorInfos: vec2f; +uniform specularColorMatrix: mat4x4f; #define ADDITIONAL_UBO_DECLARATION 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..a56f7056b55 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -0,0 +1,34 @@ +var finalColor: vec4f = vec4f( +#ifndef UNLIT + #ifdef REFLECTION + finalIrradiance + + #endif + #ifdef SPECULARTERM + finalSpecularScaled + + #endif + #ifdef REFLECTION + finalRadianceScaled + + #endif +#endif + finalAmbient + + 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 + finalEmissive, 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 index 363fde264fe..9fb632b5df8 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -5,41 +5,11 @@ #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) -#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_SAMPLERNAME_,reflectivity) -#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_SAMPLERNAME_,microSurface) -#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_SAMPLERNAME_,metallicReflectance) -#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_SAMPLERNAME_,reflectance) +#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_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_SAMPLERNAME_,clearCoat) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) - var clearCoatRoughnessSamplerSampler: sampler; - var clearCoatRoughnessSampler: texture_2d; - #endif - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_SAMPLERNAME_,clearCoatBump) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_SAMPLERNAME_,clearCoatTint) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_SAMPLERNAME_,iridescence) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_SAMPLERNAME_,iridescenceThickness) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_SAMPLERNAME_,sheen) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) - #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) - var sheenRoughnessSamplerSampler: sampler; - var sheenRoughnessSampler: texture_2d; - #endif -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_SAMPLERNAME_,anisotropy) -#endif - // Reflection #ifdef REFLECTION #ifdef REFLECTIONMAP_3D @@ -91,43 +61,6 @@ var environmentBrdfSampler: texture_2d; #endif - -// SUBSURFACE -#ifdef SUBSURFACE - #ifdef SS_REFRACTION - #ifdef SS_REFRACTIONMAP_3D - - var refractionSamplerSampler: sampler; - var refractionSampler: texture_cube; - - #ifdef LODBASEDMICROSFURACE - #else - var refractionLowSamplerSampler: sampler; - var refractionLowSampler: texture_cube; - var refractionHighSamplerSampler: sampler; - var refractionHighSampler: texture_cube; - #endif - #else - - var refractionSamplerSampler: sampler; - var refractionSampler: texture_2d; - - #ifdef LODBASEDMICROSFURACE - #else - var refractionLowSamplerSampler: sampler; - var refractionLowSampler: texture_2d; - var refractionHighSamplerSampler: sampler; - var refractionHighSampler: texture_2d; - #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 var icdfSamplerSampler: sampler; var icdfSampler: texture_2d; diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index f7e3de2798a..c664ab9513c 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -45,15 +45,10 @@ #define CUSTOM_FRAGMENT_DEFINITIONS #include -#include +#include #include #include -#include #include -#include -#include -#include -#include // _____________________________ MAIN FUNCTION ____________________________ @fragment @@ -93,12 +88,12 @@ fn main(input: FragmentInputs) -> FragmentOutputs { uniforms.vBaseColor #ifdef ALBEDO , baseColorFromTexture - , uniforms.baseColorInfos + , uniforms.vBaseColorInfos #endif , uniforms.baseWeight #ifdef BASE_WEIGHT , baseWeightFromTexture - , uniforms.baseWeightInfos + , uniforms.vBaseWeightInfos #endif #ifdef OPACITY , opacityMap @@ -148,125 +143,70 @@ fn main(input: FragmentInputs) -> FragmentOutputs { var reflectivityOut: reflectivityOutParams; -#if defined(REFLECTIVITY) - var surfaceMetallicOrReflectivityColorMap: vec4f = textureSample(reflectivitySampler, reflectivitySamplerSampler, fragmentInputs.vReflectivityUV + uvOffset); - var baseReflectivity: vec4f = surfaceMetallicOrReflectivityColorMap; - #ifndef METALLICWORKFLOW - #ifdef REFLECTIVITY_GAMMA - surfaceMetallicOrReflectivityColorMap = toLinearSpaceVec4(surfaceMetallicOrReflectivityColorMap); - #endif - surfaceMetallicOrReflectivityColorMap = vec4f(surfaceMetallicOrReflectivityColorMap.rgb * uniforms.vReflectivityInfos.y, surfaceMetallicOrReflectivityColorMap.a); - #endif -#endif - -#if defined(MICROSURFACEMAP) - var microSurfaceTexel: vec4f = textureSample(microSurfaceSampler, microSurfaceSamplerSampler, fragmentInputs.vMicroSurfaceSamplerUV + uvOffset) * uniforms.vMicroSurfaceSamplerInfos.y; +#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 -#ifdef METALLICWORKFLOW - var metallicReflectanceFactors: vec4f = uniforms.vMetallicReflectanceFactors; - #ifdef REFLECTANCE - var reflectanceFactorsMap: vec4f = textureSample(reflectanceSampler, reflectanceSamplerSampler, fragmentInputs.vReflectanceUV + uvOffset); - #ifdef REFLECTANCE_GAMMA - reflectanceFactorsMap = toLinearSpaceVec4(reflectanceFactorsMap); - #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 - metallicReflectanceFactors = vec4f(metallicReflectanceFactors.rgb * reflectanceFactorsMap.rgb, metallicReflectanceFactors.a); + 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 - #ifdef METALLIC_REFLECTANCE - var metallicReflectanceFactorsMap: vec4f = textureSample(metallicReflectanceSampler, metallicReflectanceSamplerSampler, fragmentInputs.vMetallicReflectanceUV + uvOffset); - #ifdef METALLIC_REFLECTANCE_GAMMA - metallicReflectanceFactorsMap = toLinearSpaceVec4(metallicReflectanceFactorsMap); - #endif - #ifndef METALLIC_REFLECTANCE_USE_ALPHA_ONLY - metallicReflectanceFactors = vec4f(metallicReflectanceFactors.rgb * metallicReflectanceFactorsMap.rgb, metallicReflectanceFactors.a); - #endif - metallicReflectanceFactors.a *= metallicReflectanceFactorsMap.a; + // 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.vReflectivityColor - #ifdef METALLICWORKFLOW + uniforms.vReflectanceInfo , surfaceAlbedo - , metallicReflectanceFactors - #endif - , uniforms.baseDiffuseRoughness + , specularColor + , uniforms.vBaseDiffuseRoughness #ifdef BASE_DIFFUSE_ROUGHNESS , baseDiffuseRoughnessFromTexture - , uniforms.baseDiffuseRoughnessInfos + , uniforms.vBaseDiffuseRoughnessInfos #endif - #ifdef REFLECTIVITY - , uniforms.vReflectivityInfos - , surfaceMetallicOrReflectivityColorMap + #ifdef METALLIC_ROUGHNESS + , vec3f(uniforms.vBaseMetalRoughInfos, 1.0f) + , metallicRoughnessFromTexture #endif - #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) , aoOut.ambientOcclusionColor #endif - #ifdef MICROSURFACEMAP - , microSurfaceTexel - #endif #ifdef DETAIL , detailColor , uniforms.vDetailInfos #endif ); - var microSurface: f32 = reflectivityOut.microSurface; var roughness: f32 = reflectivityOut.roughness; var diffuseRoughness: f32 = reflectivityOut.diffuseRoughness; - #ifdef METALLICWORKFLOW - surfaceAlbedo = reflectivityOut.surfaceAlbedo; - #endif - #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY) && defined(AOSTOREINMETALMAPRED) + #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; #endif - // _____________________________ Alpha Fresnel ___________________________________ - #ifdef ALPHAFRESNEL - #if defined(ALPHATEST) || defined(ALPHABLEND) - var alphaFresnelOut: alphaFresnelOutParams; - - alphaFresnelOut = alphaFresnelBlock( - normalW, - viewDirectionW, - alpha, - microSurface - ); - - alpha = alphaFresnelOut.alpha; - #endif - #endif - // _____________________________ Compute Geometry info _________________________________ #include - // _____________________________ Anisotropy _______________________________________ - #ifdef ANISOTROPIC - var anisotropicOut: anisotropicOutParams; - - #ifdef ANISOTROPIC_TEXTURE - var anisotropyMapData: vec3f = textureSample(anisotropySampler, anisotropySamplerSampler, fragmentInputs.vAnisotropyUV + uvOffset).rgb * uniforms.vAnisotropyInfos.y; - #endif - - anisotropicOut = anisotropicBlock( - uniforms.vAnisotropy, - roughness, - #ifdef ANISOTROPIC_TEXTURE - anisotropyMapData, - #endif - TBN, - normalW, - viewDirectionW - ); - #endif - // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION var reflectionOut: reflectionOutParams; @@ -284,9 +224,6 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) , NdotVUnclamped - #endif - #ifdef LINEARSPECULARREFLECTION - , roughness #endif , reflectionSampler , reflectionSamplerSampler @@ -326,336 +263,34 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif // ___________________ Compute Reflectance aka R0 F0 info _________________________ - #include - - // ________________________________ Sheen ______________________________ - #ifdef SHEEN - var sheenOut: sheenOutParams; - - #ifdef SHEEN_TEXTURE - var sheenMapData: vec4f = textureSample(sheenSampler, sheenSamplerSampler, fragmentInputs.vSheenUV + uvOffset); - #endif - #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) - var sheenMapRoughnessData: vec4f = textureSample(sheenRoughnessSampler, sheenRoughnessSamplerSampler, fragmentInputs.vSheenRoughnessUV + uvOffset) * uniforms.vSheenInfos.w; - #endif - - sheenOut = sheenBlock( - uniforms.vSheenColor - #ifdef SHEEN_ROUGHNESS - , uniforms.vSheenRoughness - #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_USE_ROUGHNESS_FROM_MAINTEXTURE) - , sheenMapRoughnessData - #endif - #endif - , roughness - #ifdef SHEEN_TEXTURE - , sheenMapData - , uniforms.vSheenInfos.y - #endif - , reflectanceF0 - #ifdef SHEEN_LINKWITHALBEDO - , baseColor - , surfaceAlbedo - #endif - #ifdef ENVIRONMENTBRDF - , NdotV - , environmentBrdf - #endif - #if defined(REFLECTION) && defined(ENVIRONMENTBRDF) - , AARoughnessFactors - , uniforms.vReflectionMicrosurfaceInfos - , uniforms.vReflectionInfos - , uniforms.vReflectionColor - , uniforms.vLightingIntensity - , reflectionSampler - , reflectionSamplerSampler - , reflectionOut.reflectionCoords - , NdotVUnclamped - #ifndef LODBASEDMICROSFURACE - , reflectionLowSampler - , reflectionLowSamplerSampler - , reflectionHighSampler - , reflectionHighSamplerSampler - #endif - #ifdef REALTIME_FILTERING - , uniforms.vReflectionFilteringInfo - #endif - #if !defined(REFLECTIONMAP_SKYBOX) && defined(RADIANCEOCCLUSION) - , seo - #endif - #if !defined(REFLECTIONMAP_SKYBOX) && defined(HORIZONOCCLUSION) && defined(BUMP) && defined(REFLECTIONMAP_3D) - , eho - #endif - #endif - ); - - #ifdef SHEEN_LINKWITHALBEDO - surfaceAlbedo = sheenOut.surfaceAlbedo; - #endif - #endif - - // _____________ Shared Iridescence and Clear Coat data _________________ - #ifdef CLEARCOAT - #ifdef CLEARCOAT_TEXTURE - var clearCoatMapData: vec2f = textureSample(clearCoatSampler, clearCoatSamplerSampler, fragmentInputs.vClearCoatUV + uvOffset).rg * uniforms.vClearCoatInfos.y; - #endif - #endif - - // _____________________________ Iridescence ____________________________ - #ifdef IRIDESCENCE - var iridescenceOut: iridescenceOutParams; - - #ifdef IRIDESCENCE_TEXTURE - var iridescenceMapData: vec2f = textureSample(iridescenceSampler, iridescenceSamplerSampler, fragmentInputs.vIridescenceUV + uvOffset).rg * uniforms.vIridescenceInfos.y; - #endif - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - var iridescenceThicknessMapData: vec2f = textureSample(iridescenceThicknessSampler, iridescenceThicknessSamplerSampler, fragmentInputs.vIridescenceThicknessUV + uvOffset).rg * uniforms.vIridescenceInfos.w; - #endif - - iridescenceOut = iridescenceBlock( - uniforms.vIridescenceParams - , NdotV - , specularEnvironmentR0 - #ifdef IRIDESCENCE_TEXTURE - , iridescenceMapData - #endif - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - , iridescenceThicknessMapData - #endif - #ifdef CLEARCOAT - , NdotVUnclamped - , uniforms.vClearCoatParams - #ifdef CLEARCOAT_TEXTURE - , clearCoatMapData - #endif - #endif - ); - - var iridescenceIntensity: f32 = iridescenceOut.iridescenceIntensity; - specularEnvironmentR0 = iridescenceOut.specularEnvironmentR0; - #endif - - // _____________________________ Clear Coat ____________________________ - var clearcoatOut: clearcoatOutParams; - - #ifdef CLEARCOAT - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) - var clearCoatMapRoughnessData: vec4f = textureSample(clearCoatRoughnessSampler, clearCoatRoughnessSamplerSampler, fragmentInputs.vClearCoatRoughnessUV + uvOffset) * uniforms.vClearCoatInfos.w; - #endif - - #if defined(CLEARCOAT_TINT) && defined(CLEARCOAT_TINT_TEXTURE) - var clearCoatTintMapData: vec4f = textureSample(clearCoatTintSampler, clearCoatTintSamplerSampler, fragmentInputs.vClearCoatTintUV + uvOffset); - #endif - - #ifdef CLEARCOAT_BUMP - var clearCoatBumpMapData: vec4f = textureSample(clearCoatBumpSampler, clearCoatBumpSamplerSampler, fragmentInputs.vClearCoatBumpUV + uvOffset); - #endif - - clearcoatOut = clearcoatBlock( - fragmentInputs.vPositionW - , geometricNormalW - , viewDirectionW - , uniforms.vClearCoatParams - #if defined(CLEARCOAT_TEXTURE_ROUGHNESS) && !defined(CLEARCOAT_USE_ROUGHNESS_FROM_MAINTEXTURE) - , clearCoatMapRoughnessData - #endif - , specularEnvironmentR0 - #ifdef CLEARCOAT_TEXTURE - , clearCoatMapData - #endif - #ifdef CLEARCOAT_TINT - , uniforms.vClearCoatTintParams - , uniforms.clearCoatColorAtDistance - , uniforms.vClearCoatRefractionParams - #ifdef CLEARCOAT_TINT_TEXTURE - , clearCoatTintMapData - #endif - #endif - #ifdef CLEARCOAT_BUMP - , uniforms.vClearCoatBumpInfos - , clearCoatBumpMapData - , fragmentInputs.vClearCoatBumpUV - #if defined(TANGENT) && defined(NORMAL) - , mat3x3(input.vTBN0, input.vTBN1, input.vTBN2) - #else - , uniforms.vClearCoatTangentSpaceParams - #endif - #ifdef OBJECTSPACE_NORMALMAP - , uniforms.normalMatrix - #endif - #endif - #if defined(FORCENORMALFORWARD) && defined(NORMAL) - , faceNormal - #endif - #ifdef REFLECTION - , uniforms.vReflectionMicrosurfaceInfos - , uniforms.vReflectionInfos - , uniforms.vReflectionColor - , uniforms.vLightingIntensity - , reflectionSampler - , reflectionSamplerSampler - #ifndef LODBASEDMICROSFURACE - , reflectionLowSampler - , reflectionLowSamplerSampler - , reflectionHighSampler - , reflectionHighSamplerSampler - #endif - #ifdef REALTIME_FILTERING - , uniforms.vReflectionFilteringInfo - #endif - #endif - #if defined(CLEARCOAT_BUMP) || defined(TWOSIDEDLIGHTING) - , select(-1., 1., fragmentInputs.frontFacing) - #endif - ); - #else - clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0; - #endif + var reflectanceF0: f32 = reflectivityOut.reflectanceF0; + var specularEnvironmentR0: vec3f = reflectivityOut.colorReflectanceF0; + var specularEnvironmentR90: vec3f = reflectivityOut.colorReflectanceF90; // _________________________ Specular Environment Reflectance __________________________ - #include - - // ___________________________________ SubSurface ______________________________________ - var subSurfaceOut: subSurfaceOutParams; - - #ifdef SUBSURFACE - #ifdef SS_THICKNESSANDMASK_TEXTURE - var thicknessMap: vec4f = textureSample(thicknessSampler, thicknessSamplerSampler, fragmentInputs.vThicknessUV + uvOffset); - #endif - - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - var refractionIntensityMap: vec4f = textureSample(refractionIntensitySampler, refractionIntensitySamplerSampler, fragmentInputs.vRefractionIntensityUV + uvOffset); - #endif - - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - var translucencyIntensityMap: vec4f = textureSample(translucencyIntensitySampler, translucencyIntensitySamplerSampler, fragmentInputs.vTranslucencyIntensityUV + uvOffset); - #endif - - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - var translucencyColorMap: vec4f = textureSample(translucencyColorSampler, translucencyColorSamplerSampler, fragmentInputs.vTranslucencyColorUV + uvOffset); - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE_GAMMA - translucencyColorMap = toLinearSpaceVec4(translucencyColorMap); - #endif - #endif - - subSurfaceOut = subSurfaceBlock( - uniforms.vSubSurfaceIntensity - , uniforms.vThicknessParam - , uniforms.vTintColor - , normalW - #ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION - , vec3f(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b))) - #else - , baseSpecularEnvironmentReflectance - #endif - #ifdef SS_THICKNESSANDMASK_TEXTURE - , thicknessMap - #endif - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - , refractionIntensityMap - #endif - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - , translucencyIntensityMap - #endif - #ifdef REFLECTION - #ifdef SS_TRANSLUCENCY - , uniforms.reflectionMatrix - #ifdef USESPHERICALFROMREFLECTIONMAP - #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) - , reflectionOut.irradianceVector - #endif - #if defined(REALTIME_FILTERING) - , reflectionSampler - , reflectionSamplerSampler - , uniforms.vReflectionFilteringInfo - #ifdef IBL_CDF_FILTERING - , icdfSampler - , icdfSamplerSampler - #endif - #endif - #endif - #ifdef USEIRRADIANCEMAP - , irradianceSampler - , irradianceSamplerSampler - #endif - #endif - #endif - #if defined(SS_REFRACTION) || defined(SS_TRANSLUCENCY) - , surfaceAlbedo - #endif - #ifdef SS_REFRACTION - , fragmentInputs.vPositionW - , viewDirectionW - , scene.view - , uniforms.vRefractionInfos - , uniforms.refractionMatrix - , uniforms.vRefractionMicrosurfaceInfos - , uniforms.vLightingIntensity - #ifdef SS_LINKREFRACTIONTOTRANSPARENCY - , alpha - #endif - #ifdef SS_LODINREFRACTIONALPHA - , NdotVUnclamped - #endif - #ifdef SS_LINEARSPECULARREFRACTION - , roughness - #endif - , alphaG - , refractionSampler - , refractionSamplerSampler - #ifndef LODBASEDMICROSFURACE - , refractionLowSampler - , refractionLowSamplerSampler - , refractionHighSampler - , refractionHighSamplerSampler - #endif - #ifdef ANISOTROPIC - , anisotropicOut - #endif - #ifdef REALTIME_FILTERING - , uniforms.vRefractionFilteringInfo - #endif - #ifdef SS_USE_LOCAL_REFRACTIONMAP_CUBIC - , uniforms.vRefractionPosition - , uniforms.vRefractionSize - #endif - #ifdef SS_DISPERSION - , dispersion - #endif - #endif - #ifdef SS_TRANSLUCENCY - , uniforms.vDiffusionDistance - , uniforms.vTranslucencyColor - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - , translucencyColorMap - #endif - #endif - ); - - #ifdef SS_REFRACTION - surfaceAlbedo = subSurfaceOut.surfaceAlbedo; - #ifdef SS_LINKREFRACTIONTOTRANSPARENCY - alpha = subSurfaceOut.alpha; - #endif - #endif - #else - subSurfaceOut.specularEnvironmentReflectance = colorSpecularEnvironmentReflectance; - #endif + #include // _____________________________ Direct Lighting Info __________________________________ #include - - #include[0..maxSimultaneousLights] + // 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 + #include #endif // UNLIT #include #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - #include + #include #include #include(color, finalColor) diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 493232d3fa5..87435b5a65a 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -37,41 +37,12 @@ attribute color: vec4f; #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) -#include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity) -#include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler) -#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance) -#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance) +#include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) +#include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) +#include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) #include(_DEFINENAME_,BUMP,_VARYINGNAME_,Bump) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness) - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness) -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy) -#endif - -#ifdef SUBSURFACE - #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness) - #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity) - #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity) - #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor) -#endif - // Output varying vPositionW: vec3f; #if DEBUGMODE > 0 @@ -179,7 +150,7 @@ fn main(input : VertexInputs) -> FragmentInputs { // 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.baseDiffuseRoughness); + 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; @@ -228,7 +199,7 @@ fn main(input : VertexInputs) -> FragmentInputs { #include[3..7] - #include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_MATRIXNAME_,baseColor,_INFONAME_,baseColorInfos.x) + #include(_DEFINENAME_,ALBEDO,_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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) @@ -236,42 +207,12 @@ fn main(input : VertexInputs) -> FragmentInputs { #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.x) - #include(_DEFINENAME_,REFLECTIVITY,_VARYINGNAME_,Reflectivity,_MATRIXNAME_,reflectivity,_INFONAME_,ReflectivityInfos.x) - #include(_DEFINENAME_,MICROSURFACEMAP,_VARYINGNAME_,MicroSurfaceSampler,_MATRIXNAME_,microSurfaceSampler,_INFONAME_,MicroSurfaceSamplerInfos.x) - #include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_MATRIXNAME_,metallicReflectance,_INFONAME_,MetallicReflectanceInfos.x) - #include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_MATRIXNAME_,reflectance,_INFONAME_,ReflectanceInfos.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_,BUMP,_VARYINGNAME_,Bump,_MATRIXNAME_,bump,_INFONAME_,BumpInfos.x) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) -#ifdef CLEARCOAT - #include(_DEFINENAME_,CLEARCOAT_TEXTURE,_VARYINGNAME_,ClearCoat,_MATRIXNAME_,clearCoat,_INFONAME_,ClearCoatInfos.x) - #include(_DEFINENAME_,CLEARCOAT_TEXTURE_ROUGHNESS,_VARYINGNAME_,ClearCoatRoughness,_MATRIXNAME_,clearCoatRoughness,_INFONAME_,ClearCoatInfos.z) - #include(_DEFINENAME_,CLEARCOAT_BUMP,_VARYINGNAME_,ClearCoatBump,_MATRIXNAME_,clearCoatBump,_INFONAME_,ClearCoatBumpInfos.x) - #include(_DEFINENAME_,CLEARCOAT_TINT_TEXTURE,_VARYINGNAME_,ClearCoatTint,_MATRIXNAME_,clearCoatTint,_INFONAME_,ClearCoatTintInfos.x) -#endif - -#ifdef IRIDESCENCE - #include(_DEFINENAME_,IRIDESCENCE_TEXTURE,_VARYINGNAME_,Iridescence,_MATRIXNAME_,iridescence,_INFONAME_,IridescenceInfos.x) - #include(_DEFINENAME_,IRIDESCENCE_THICKNESS_TEXTURE,_VARYINGNAME_,IridescenceThickness,_MATRIXNAME_,iridescenceThickness,_INFONAME_,IridescenceInfos.z) -#endif - -#ifdef SHEEN - #include(_DEFINENAME_,SHEEN_TEXTURE,_VARYINGNAME_,Sheen,_MATRIXNAME_,sheen,_INFONAME_,SheenInfos.x) - #include(_DEFINENAME_,SHEEN_TEXTURE_ROUGHNESS,_VARYINGNAME_,SheenRoughness,_MATRIXNAME_,sheenRoughness,_INFONAME_,SheenInfos.z) - -#endif - -#ifdef ANISOTROPIC - #include(_DEFINENAME_,ANISOTROPIC_TEXTURE,_VARYINGNAME_,Anisotropy,_MATRIXNAME_,anisotropy,_INFONAME_,AnisotropyInfos.x) -#endif - -#ifdef SUBSURFACE - #include(_DEFINENAME_,SS_THICKNESSANDMASK_TEXTURE,_VARYINGNAME_,Thickness,_MATRIXNAME_,thickness,_INFONAME_,ThicknessInfos.x) - #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_MATRIXNAME_,refractionIntensity,_INFONAME_,RefractionIntensityInfos.x) - #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_MATRIXNAME_,translucencyIntensity,_INFONAME_,TranslucencyIntensityInfos.x) - #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_MATRIXNAME_,translucencyColor,_INFONAME_,TranslucencyColorInfos.x) -#endif - // TBN #include 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 7eb0ceafa45..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 @@ -73,14 +73,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component - + {material instanceof PBRMaterial && ( + + )} )} - - + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} - (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} + /> + )} {material instanceof PBRMaterial && ( <> diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts index 1d35b075425..4f228ad3d07 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts @@ -1,7 +1,6 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; 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"; @@ -75,7 +74,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax private _loadSpecularGlossinessPropertiesAsync(context: string, properties: IKHRMaterialsPbrSpecularGlossiness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterial)) { throw new Error(`${context}: Material type not supported`); } @@ -85,18 +84,10 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension babylonMaterial.roughness = null; if (properties.diffuseFactor) { - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColor = Color3.FromArray(properties.diffuseFactor); - } else { - babylonMaterial.albedoColor = Color3.FromArray(properties.diffuseFactor); - } + babylonMaterial.albedoColor = Color3.FromArray(properties.diffuseFactor); babylonMaterial.alpha = properties.diffuseFactor[3]; } else { - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColor = Color3.White(); - } else { - babylonMaterial.albedoColor = Color3.White(); - } + babylonMaterial.albedoColor = Color3.White(); } babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : Color3.White(); @@ -106,11 +97,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension promises.push( this._loader.loadTextureInfoAsync(`${context}/diffuseTexture`, properties.diffuseTexture, (texture) => { texture.name = `${babylonMaterial.name} (Diffuse)`; - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColorTexture = texture; - } else { - babylonMaterial.albedoTexture = texture; - } + babylonMaterial.albedoTexture = texture; }) ); } 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 a55f058dca1..ae0db035daf 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 @@ -90,32 +90,62 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { const promises = new Array>(); - if (properties.specularFactor !== undefined) { - babylonMaterial.metallicF0Factor = properties.specularFactor; - } + if (babylonMaterial instanceof OpenPBRMaterial) { + if (properties.specularFactor !== undefined) { + babylonMaterial.specularWeight = properties.specularFactor; + } - if (properties.specularColorFactor !== undefined) { - babylonMaterial.metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); - } + if (properties.specularColorFactor !== undefined) { + babylonMaterial.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.specularWeightTexture = texture; + babylonMaterial.useSpecularWeightFromTextureAlpha = true; + }) + ); + } + + if (properties.specularColorTexture) { + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular Color)`; + babylonMaterial.specularColorTexture = texture; + }) + ); + } + } else { + if (properties.specularFactor !== undefined) { + babylonMaterial.metallicF0Factor = properties.specularFactor; + } + + if (properties.specularColorFactor !== undefined) { + babylonMaterial.metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); + } - if (properties.specularColorTexture) { - promises.push( - this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { - texture.name = `${babylonMaterial.name} (Specular Color)`; - babylonMaterial.reflectanceTexture = texture; - }) - ); + 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.specularColorTexture) { + promises.push( + this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { + texture.name = `${babylonMaterial.name} (Specular Color)`; + babylonMaterial.reflectanceTexture = texture; + }) + ); + } } // eslint-disable-next-line github/no-then 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 5e16205e167..76f6932f2b3 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 @@ -63,10 +63,9 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { if (!babylonMaterial.albedoTexture) { babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); } - } - - if (!babylonMaterial.reflectivityTexture) { - babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor, useExactSrgbConversions); + if (!babylonMaterial.reflectivityTexture) { + babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.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 16e5f3a8509..5a12ad340d3 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -2151,8 +2151,13 @@ export class GLTFLoader implements IGLTFLoader { } } - babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; - babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + if (babylonMaterial instanceof PBRMaterial) { + babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + } else if (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseMetalness = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + babylonMaterial.specularRoughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + } if (properties.baseColorTexture) { promises.push( @@ -2172,13 +2177,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 (babylonMaterial instanceof OpenPBRMaterial) { + babylonMaterial.baseMetalRoughTexture = texture; + } else { + babylonMaterial.metallicTexture = texture; + } }) ); - babylonMaterial.useMetallnessFromMetallicTextureBlue = true; - babylonMaterial.useRoughnessFromMetallicTextureGreen = true; - babylonMaterial.useRoughnessFromMetallicTextureAlpha = false; + if (babylonMaterial instanceof PBRMaterial) { + babylonMaterial.useMetallnessFromMetallicTextureBlue = true; + babylonMaterial.useRoughnessFromMetallicTextureGreen = true; + babylonMaterial.useRoughnessFromMetallicTextureAlpha = false; + } } } @@ -2255,8 +2266,10 @@ export class GLTFLoader implements IGLTFLoader { babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage; babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage; babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; - babylonMaterial.metallic = 1; - babylonMaterial.roughness = 1; + if (babylonMaterial instanceof PBRMaterial) { + babylonMaterial.metallic = 1; + babylonMaterial.roughness = 1; + } return babylonMaterial; } From e3bfa80b425efb037dd973778fd11778e6c03ed7 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Thu, 17 Jul 2025 13:57:17 -0700 Subject: [PATCH 19/45] Change albedo to base color --- .../core/src/Materials/PBR/openPbrMaterial.ts | 2 +- .../openpbrBlockAlbedoOpacity.fx | 115 +++++++++++++++++ .../openpbrFragmentDeclaration.fx | 2 +- .../openpbrFragmentSamplersDeclaration.fx | 2 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 7 +- .../dev/core/src/Shaders/openpbr.vertex.fx | 4 +- .../openpbrBlockAlbedoOpacity.fx | 116 ++++++++++++++++++ .../openpbrFragmentSamplersDeclaration.fx | 2 +- .../core/src/ShadersWGSL/openpbr.fragment.fx | 6 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 4 +- 10 files changed, 245 insertions(+), 15 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 24486482428..a6f43d0eef8 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -483,7 +483,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public baseColorTexture: BaseTexture; @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "baseColorTexture") // eslint-disable-next-line @typescript-eslint/no-unused-vars - private _baseColorTexture: Sampler = new Sampler("base_color", "baseColor", "ALBEDO"); + private _baseColorTexture: Sampler = new Sampler("base_color", "baseColor", "BASE_COLOR"); /** * Roughness of the diffuse lobe. 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/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index fe2d0db835c..4bbc1106acd 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -15,7 +15,7 @@ uniform float visibility; uniform vec3 vAmbientColor; // Samplers -#ifdef ALBEDO +#ifdef BASE_COLOR uniform vec2 vBaseColorInfos; #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 24783ded67f..673e42f5069 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -1,4 +1,4 @@ -#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#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_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 18f8c4fd57d..6ce8d8bde9f 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -60,7 +60,7 @@ precision highp float; #define CUSTOM_FRAGMENT_DEFINITIONS -#include +#include #include #include #include @@ -83,7 +83,7 @@ void main(void) { // _____________________________ Albedo & Opacity ______________________________ albedoOpacityOutParams albedoOpacityOut; -#ifdef ALBEDO +#ifdef BASE_COLOR vec4 baseColorFromTexture = texture2D(baseColorSampler, vBaseColorUV + uvOffset); #endif @@ -101,7 +101,7 @@ void main(void) { albedoOpacityOut = albedoOpacityBlock( vBaseColor - #ifdef ALBEDO + #ifdef BASE_COLOR , baseColorFromTexture , vBaseColorInfos #endif @@ -145,7 +145,6 @@ void main(void) { - // _____________________________ AO _______________________________ ambientOcclusionOutParams aoOut; diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 3bf844c7304..7836a4b20ee 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -33,7 +33,7 @@ attribute vec4 color; #include #include -#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,Albedo) +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor) #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) @@ -212,7 +212,7 @@ void main(void) { #include[3..7] - #include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,Albedo,_MATRIXNAME_,albedo,_INFONAME_,AlbedoInfos.x) + #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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) 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/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 9fb632b5df8..dd80615a595 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -1,4 +1,4 @@ -#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_SAMPLERNAME_,baseColor) +#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_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index c664ab9513c..c7c5c09738d 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -44,7 +44,7 @@ #define CUSTOM_FRAGMENT_DEFINITIONS -#include +#include #include #include #include @@ -68,7 +68,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs { // _____________________________ Albedo & Opacity ______________________________ var albedoOpacityOut: albedoOpacityOutParams; -#ifdef ALBEDO +#ifdef BASE_COLOR var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, fragmentInputs.vBaseColorUV + uvOffset); #endif @@ -86,7 +86,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs { albedoOpacityOut = albedoOpacityBlock( uniforms.vBaseColor - #ifdef ALBEDO + #ifdef BASE_COLOR , baseColorFromTexture , uniforms.vBaseColorInfos #endif diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 87435b5a65a..10fc816f04f 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -29,7 +29,7 @@ attribute color: vec4f; #include #include -#include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,Albedo) +#include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,Albedo) #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) @@ -199,7 +199,7 @@ fn main(input : VertexInputs) -> FragmentInputs { #include[3..7] - #include(_DEFINENAME_,ALBEDO,_VARYINGNAME_,BaseColor,_MATRIXNAME_,baseColor,_INFONAME_,BaseColorInfos.x) + #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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) From 48b9e4de59758d092fdbdfd8519dd13291ad6be2 Mon Sep 17 00:00:00 2001 From: Michael Bond Date: Thu, 10 Jul 2025 12:34:52 -0700 Subject: [PATCH 20/45] WIP glTFLoader dynamic material load --- .../Extensions/KHR_materials_anisotropy.ts | 24 +++-- .../2.0/Extensions/KHR_materials_clearcoat.ts | 70 +++++++++---- .../KHR_materials_diffuse_transmission.ts | 77 +++++++++------ .../Extensions/KHR_materials_dispersion.ts | 40 +++++--- .../KHR_materials_emissive_strength.ts | 17 +++- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 29 ++++-- .../Extensions/KHR_materials_iridescence.ts | 54 +++++++--- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 98 +++++++++---------- 8 files changed, 270 insertions(+), 139 deletions(-) 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..a9d2cb7e2eb 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,8 +63,15 @@ 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); @@ -70,23 +80,23 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { } 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..034c3b49f8b 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) => { + 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`); + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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..91930aef943 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,8 +69,15 @@ 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadTranslucentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); @@ -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..31bbbf7b404 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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 47785510fe7..0b334915f2c 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -22,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) */ @@ -61,8 +63,15 @@ 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) => { + 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; + } // eslint-disable-next-line github/no-then return await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial).then(() => { this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); @@ -71,7 +80,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { } private _loadEmissiveProperties(context: string, properties: IKHRMaterialsEmissiveStrength, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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..6c3479fa586 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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..22271fa7961 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); + 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/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 5a12ad340d3..9b91b05253d 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -16,8 +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 { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -87,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; @@ -400,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]}`; @@ -2128,45 +2138,44 @@ export class GLTFLoader implements IGLTFLoader { } private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, properties: IMaterialPbrMetallicRoughness, babylonMaterial: Material): Promise { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); if (properties) { - if (babylonMaterial instanceof OpenPBRMaterial) { + if (this.parent.useOpenPBR) { + const mat = babylonMaterial as OpenPBRMaterial; if (properties.baseColorFactor) { - babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.geometryOpacity = properties.baseColorFactor[3]; + mat.baseColor = Color3.FromArray(properties.baseColorFactor); + mat.geometryOpacity = properties.baseColorFactor[3]; } else { - babylonMaterial.baseColor = Color3.White(); + mat.baseColor = Color3.White(); } + mat.baseMetalness = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + mat.specularRoughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; } else { + const mat = babylonMaterial as PBRMaterial; if (properties.baseColorFactor) { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - babylonMaterial.alpha = properties.baseColorFactor[3]; + mat.albedoColor = Color3.FromArray(properties.baseColorFactor); + mat.alpha = properties.baseColorFactor[3]; } else { - babylonMaterial.albedoColor = Color3.White(); + mat.albedoColor = Color3.White(); } - } - - if (babylonMaterial instanceof PBRMaterial) { - babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; - babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; - } else if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseMetalness = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; - babylonMaterial.specularRoughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + mat.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor; + mat.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor; + babylonMaterial = mat; } if (properties.baseColorTexture) { promises.push( this.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Base Color)`; - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColorTexture = texture; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; } else { - babylonMaterial.albedoTexture = texture; + (babylonMaterial as PBRMaterial).albedoTexture = texture; } }) ); @@ -2177,18 +2186,18 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this.loadTextureInfoAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, (texture) => { texture.name = `${babylonMaterial.name} (Metallic Roughness)`; - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseMetalRoughTexture = texture; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseMetalRoughTexture = texture; } else { - babylonMaterial.metallicTexture = texture; + (babylonMaterial as PBRMaterial).metallicTexture = texture; } }) ); - if (babylonMaterial instanceof PBRMaterial) { - 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; } } } @@ -2252,12 +2261,7 @@ export class GLTFLoader implements IGLTFLoader { private _createDefaultMaterial(name: string, babylonDrawMode: number): Material { this._babylonScene._blockEntityCollection = !!this._assetContainer; - let babylonMaterial; - if (this.parent.useOpenPBR) { - babylonMaterial = new OpenPBRMaterial(name, this._babylonScene); - } else { - 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; @@ -2265,11 +2269,7 @@ export class GLTFLoader implements IGLTFLoader { babylonMaterial.enableSpecularAntiAliasing = true; babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage; babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage; - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE; - if (babylonMaterial instanceof PBRMaterial) { - babylonMaterial.metallic = 1; - babylonMaterial.roughness = 1; - } + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; return babylonMaterial; } @@ -2327,16 +2327,16 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } const promises = new Array>(); - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.emissionColor = 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.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); + (babylonMaterial as PBRMaterial).emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0); } if (material.doubleSided) { babylonMaterial.backFaceCulling = false; @@ -2396,21 +2396,21 @@ export class GLTFLoader implements IGLTFLoader { * @param babylonMaterial The Babylon material */ public loadMaterialAlphaProperties(context: string, material: IMaterial, babylonMaterial: Material): void { - if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) { + if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const baseColorTexture = babylonMaterial instanceof OpenPBRMaterial ? babylonMaterial.baseColorTexture : babylonMaterial.albedoTexture; + 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 (baseColorTexture) { baseColorTexture.hasAlpha = true; @@ -2418,7 +2418,7 @@ export class GLTFLoader implements IGLTFLoader { break; } case MaterialAlphaMode.BLEND: { - babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND; + babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_ALPHABLEND; if (baseColorTexture) { baseColorTexture.hasAlpha = true; babylonMaterial.useAlphaFromAlbedoTexture = true; @@ -2939,7 +2939,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) ); } From b9382acd017f4e922adf3864ed2e47de42072ffa Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 11 Jul 2025 08:42:43 -0700 Subject: [PATCH 21/45] Finish glTFLoader dynamic material load --- .../2.0/Extensions/KHR_materials_sheen.ts | 59 ++++++---- .../2.0/Extensions/KHR_materials_specular.ts | 27 +++-- .../Extensions/KHR_materials_transmission.ts | 104 +++++++++++------- .../2.0/Extensions/KHR_materials_volume.ts | 81 ++++++++++---- .../glTF/2.0/Extensions/MSFT_minecraftMesh.ts | 17 ++- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 27 +++-- .../src/glTF/2.0/glTFLoaderExtension.ts | 3 +- 7 files changed, 217 insertions(+), 101 deletions(-) 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..2a2a734fa02 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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 ae0db035daf..94dc328cf07 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,6 +1,6 @@ import type { Nullable } from "core/types"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -24,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) */ @@ -63,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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial)); + 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 @@ -83,8 +92,8 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material, useOpenPBR: boolean): Promise { + 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_transmission.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts index 5f91a41d555..b404b2d822f 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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_volume.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_volume.ts index 349cbd67c10..6b70b2453bf 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) => { + 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; + } const promises = new Array>(); promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); - promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension)); + 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 f52207f3e74..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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -21,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 { @@ -45,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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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 76f6932f2b3..4283dc3a8c7 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,7 +1,7 @@ import type { Nullable } from "core/types"; import type { Material } from "core/Materials/material"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -21,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 { @@ -45,23 +47,30 @@ 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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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 instanceof OpenPBRMaterial) { - if (!babylonMaterial.baseColorTexture) { - babylonMaterial.baseColor.toLinearSpaceToRef(babylonMaterial.baseColor, useExactSrgbConversions); + if (useOpenPBR) { + if (!(babylonMaterial as OpenPBRMaterial).baseColorTexture) { + (babylonMaterial as OpenPBRMaterial).baseColor.toLinearSpaceToRef((babylonMaterial as OpenPBRMaterial).baseColor, useExactSrgbConversions); } } else { - if (!babylonMaterial.albedoTexture) { - babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor, useExactSrgbConversions); + if (!(babylonMaterial as PBRMaterial).albedoTexture) { + (babylonMaterial as PBRMaterial).albedoColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).albedoColor, useExactSrgbConversions); } if (!babylonMaterial.reflectivityTexture) { babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor, useExactSrgbConversions); 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. From fe5a1fdb67aa40c6a198f3f90abf7642c4119c88 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 18 Jul 2025 10:12:26 -0700 Subject: [PATCH 22/45] Fix dynamic loading of materials in glTF loader --- .../Extensions/KHR_materials_anisotropy.ts | 4 +- .../2.0/Extensions/KHR_materials_clearcoat.ts | 4 +- .../KHR_materials_diffuse_transmission.ts | 4 +- .../Extensions/KHR_materials_dispersion.ts | 4 +- .../KHR_materials_emissive_strength.ts | 7 ++- .../glTF/2.0/Extensions/KHR_materials_ior.ts | 4 +- .../Extensions/KHR_materials_iridescence.ts | 4 +- .../2.0/Extensions/KHR_materials_sheen.ts | 4 +- .../2.0/Extensions/KHR_materials_specular.ts | 26 ++++----- .../Extensions/KHR_materials_transmission.ts | 4 +- .../2.0/Extensions/KHR_materials_unlit.ts | 53 +++++++++++-------- .../2.0/Extensions/KHR_materials_volume.ts | 4 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 4 +- 13 files changed, 66 insertions(+), 60 deletions(-) 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 a9d2cb7e2eb..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 @@ -65,6 +65,8 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -72,8 +74,6 @@ export class KHR_materials_anisotropy implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial)); await Promise.all(promises); }); 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 034c3b49f8b..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 @@ -67,6 +67,8 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -77,8 +79,6 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); await Promise.all(promises); }); 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 91930aef943..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 @@ -71,6 +71,8 @@ export class KHR_materials_diffuse_transmission implements IGLTFLoaderExtension // eslint-disable-next-line no-restricted-syntax 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; @@ -78,8 +80,6 @@ export class KHR_materials_diffuse_transmission implements IGLTFLoaderExtension const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadTranslucentPropertiesAsync(extensionContext, material, babylonMaterial, extension)); return await Promise.all(promises).then(() => {}); }); 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 31bbbf7b404..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 @@ -66,6 +66,8 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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)); if (useOpenPBR) { const mod = await import("core/Materials/PBR/openPbrMaterial"); PBRMaterialClass = mod.OpenPBRMaterial; @@ -73,8 +75,6 @@ export class KHR_materials_dispersion implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadDispersionPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 0b334915f2c..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 @@ -65,6 +65,7 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable> { return GLTFLoader.LoadExtensionAsync(context, material, this.name, async (extensionContext, extension) => { + await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial); if (useOpenPBR) { const mod = await import("core/Materials/PBR/openPbrMaterial"); PBRMaterialClass = mod.OpenPBRMaterial; @@ -72,10 +73,8 @@ export class KHR_materials_emissive_strength implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - // eslint-disable-next-line github/no-then - return await this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial).then(() => { - this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); - }); + this._loadEmissiveProperties(extensionContext, extension, babylonMaterial); + return await Promise.resolve(); }); } 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 6c3479fa586..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 @@ -70,6 +70,8 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -77,8 +79,6 @@ export class KHR_materials_ior implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIorPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 22271fa7961..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 @@ -66,6 +66,8 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -73,8 +75,6 @@ export class KHR_materials_iridescence implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadIridescencePropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 2a2a734fa02..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 @@ -68,6 +68,8 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -75,8 +77,6 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 94dc328cf07..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 @@ -67,6 +67,8 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -74,8 +76,6 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); 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 @@ -99,13 +99,13 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { const promises = new Array>(); - if (babylonMaterial instanceof OpenPBRMaterial) { + if (useOpenPBR) { if (properties.specularFactor !== undefined) { - babylonMaterial.specularWeight = properties.specularFactor; + (babylonMaterial as OpenPBRMaterial).specularWeight = properties.specularFactor; } if (properties.specularColorFactor !== undefined) { - babylonMaterial.specularColor = Color3.FromArray(properties.specularColorFactor); + (babylonMaterial as OpenPBRMaterial).specularColor = Color3.FromArray(properties.specularColorFactor); } if (properties.specularTexture) { @@ -113,8 +113,8 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => { texture.name = `${babylonMaterial.name} (Specular)`; - babylonMaterial.specularWeightTexture = texture; - babylonMaterial.useSpecularWeightFromTextureAlpha = true; + (babylonMaterial as OpenPBRMaterial).specularWeightTexture = texture; + (babylonMaterial as OpenPBRMaterial).useSpecularWeightFromTextureAlpha = true; }) ); } @@ -123,17 +123,17 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Specular Color)`; - babylonMaterial.specularColorTexture = texture; + (babylonMaterial as OpenPBRMaterial).specularColorTexture = texture; }) ); } } else { if (properties.specularFactor !== undefined) { - babylonMaterial.metallicF0Factor = properties.specularFactor; + (babylonMaterial as PBRMaterial).metallicF0Factor = properties.specularFactor; } if (properties.specularColorFactor !== undefined) { - babylonMaterial.metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); + (babylonMaterial as PBRMaterial).metallicReflectanceColor = Color3.FromArray(properties.specularColorFactor); } if (properties.specularTexture) { @@ -141,8 +141,8 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => { texture.name = `${babylonMaterial.name} (Specular)`; - babylonMaterial.metallicReflectanceTexture = texture; - babylonMaterial.useOnlyMetallicFromMetallicReflectanceTexture = true; + (babylonMaterial as PBRMaterial).metallicReflectanceTexture = texture; + (babylonMaterial as PBRMaterial).useOnlyMetallicFromMetallicReflectanceTexture = true; }) ); } @@ -151,7 +151,7 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Specular Color)`; - babylonMaterial.reflectanceTexture = texture; + (babylonMaterial as PBRMaterial).reflectionTexture = texture; }) ); } 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 b404b2d822f..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 @@ -371,6 +371,8 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -378,8 +380,6 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 aa64856fe9e..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,7 +1,7 @@ import type { Nullable } from "core/types"; import { Color3 } from "core/Maths/math.color"; -import { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; -import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +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"; @@ -22,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) */ @@ -61,53 +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) && !(babylonMaterial instanceof OpenPBRMaterial)) { + 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) { - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColor = Color3.FromArray(properties.baseColorFactor); - } else { - babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor); - } - - babylonMaterial.alpha = properties.baseColorFactor[3]; - } else { - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColor = Color3.White(); - } 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)`; - if (babylonMaterial instanceof OpenPBRMaterial) { - babylonMaterial.baseColorTexture = texture; + if (useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseColorTexture = texture; } else { - babylonMaterial.albedoTexture = texture; + (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 6b70b2453bf..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 @@ -75,6 +75,8 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { // eslint-disable-next-line no-restricted-syntax 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; @@ -82,8 +84,6 @@ export class KHR_materials_volume implements IGLTFLoaderExtension { const mod = await import("core/Materials/PBR/pbrMaterial"); PBRMaterialClass = mod.PBRMaterial; } - const promises = new Array>(); - promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial)); promises.push(this._loadVolumePropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR)); // eslint-disable-next-line github/no-then return await Promise.all(promises).then(() => {}); 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 4283dc3a8c7..de92d12c984 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 @@ -72,8 +72,8 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { if (!(babylonMaterial as PBRMaterial).albedoTexture) { (babylonMaterial as PBRMaterial).albedoColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).albedoColor, useExactSrgbConversions); } - if (!babylonMaterial.reflectivityTexture) { - babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor, useExactSrgbConversions); + if (!(babylonMaterial as PBRMaterial).reflectivityTexture) { + (babylonMaterial as PBRMaterial).reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor, useExactSrgbConversions); } } From d4d61837dcd196b19e136683f41ee568aab989a8 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 18 Jul 2025 14:14:14 -0700 Subject: [PATCH 23/45] Add more OpenPBR properties --- .../core/src/Materials/PBR/openPbrMaterial.ts | 318 +++--------------- .../ShadersInclude/openPbrUboDeclaration.fx | 19 +- .../openpbrBlockFinalColorComposition.fx | 3 +- .../openpbrFragmentDeclaration.fx | 16 +- .../openpbrFragmentSamplersDeclaration.fx | 13 +- .../openpbrVertexDeclaration.fx | 124 +------ .../dev/core/src/Shaders/openpbr.fragment.fx | 47 ++- .../dev/core/src/Shaders/openpbr.vertex.fx | 22 +- .../ShadersInclude/openPbrUboDeclaration.fx | 20 +- .../openpbrBlockFinalColorComposition.fx | 3 +- .../openpbrFragmentSamplersDeclaration.fx | 10 +- .../core/src/ShadersWGSL/openpbr.fragment.fx | 36 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 24 +- .../glTF/2.0/Extensions/MSFT_sRGBFactors.ts | 5 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 32 +- 15 files changed, 213 insertions(+), 479 deletions(-) diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index a6f43d0eef8..d6ca912183a 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, addAccessorsForMaterialProperty } from "../../Misc/decorators"; +import { serialize, expandToProperty, serializeAsTexture, addAccessorsForMaterialProperty } from "../../Misc/decorators"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import { Scene } from "../../scene"; @@ -217,14 +217,7 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public BAKED_VERTEX_ANIMATION_TEXTURE = false; - public AMBIENT = false; - public AMBIENTDIRECTUV = 0; - public AMBIENTINGRAYSCALE = false; - - public OPACITY = false; public VERTEXALPHA = false; - public OPACITYDIRECTUV = 0; - public OPACITYRGB = false; public ALPHATEST = false; public DEPTHPREPASS = false; public ALPHABLEND = false; @@ -232,10 +225,6 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public ALPHATESTVALUE = "0.5"; public PREMULTIPLYALPHA = false; - public EMISSIVE = false; - public EMISSIVEDIRECTUV = 0; - public GAMMAEMISSIVE = false; - public REFLECTIVITY_GAMMA = false; public REFLECTIVITYDIRECTUV = 0; public SPECULARTERM = false; @@ -576,7 +565,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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 + * Defines the opacity of the material's geometry. + * See OpenPBR's specs for geometry_opacity */ public geometryOpacity: number; @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "geometryOpacity") @@ -584,12 +574,39 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { private _geometryOpacity: Property = new Property("geometry_opacity", 1.0, "vBaseColor", 4, 3); /** - * Defines the color of the material's emission. See OpenPBR's specs for emission_color + * 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(), "vEmissiveColor", 3); + 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 } = {}; @@ -627,36 +644,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public disableBumpMap: boolean = false; - /** - * AKA Occlusion Texture in other nomenclature. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientTexture: Nullable; - - /** - * AKA Occlusion Texture Intensity in other nomenclature. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientTextureStrength: number = 1.0; - - /** - * Defines how much the AO map is occluding the analytical lights (point spot...). - * 1 means it completely occludes it - * 0 mean it has no impact - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientTextureImpactOnAnalyticalLights: number = OpenPBRMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; - - /** - * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") - public opacityTexture: Nullable; - /** * Stores the reflection values in a texture. */ @@ -664,13 +651,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public reflectionTexture: Nullable; - /** - * Stores the emissive values in a texture. - */ - @serializeAsTexture() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public emissiveTexture: Nullable; - /** * Specifies that the specular weight is stored in the alpha channel of the specular weight texture. */ @@ -692,27 +672,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty", null) public lightmapTexture: Nullable; - /** - * The color of a material in ambient lighting. - */ - @serializeAsColor3("ambient") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public ambientColor = new Color3(0, 0, 0); - - /** - * AKA Specular Color in other nomenclature. - */ - @serializeAsColor3("reflectivity") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public reflectivityColor = new Color3(1, 1, 1); - - /** - * The color reflected from the material. - */ - @serializeAsColor3("reflection") - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public reflectionColor = new Color3(1.0, 1.0, 1.0); - /** * If true, the light map contains occlusion information instead of lighting info. */ @@ -741,14 +700,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty") public alphaCutOff = 0.4; - /** - * Specifies that the material will keep 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. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useSpecularOverAlpha = true; - /** * Specifies if the reflectivity texture contains the glossiness information in its alpha channel. */ @@ -832,14 +783,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - /** - * 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. - */ - @serialize() - @expandToProperty("_markAllSubMeshesAsTexturesDirty") - public useRadianceOverAlpha = true; - /** * Allows using an object space normal map (instead of tangent space). */ @@ -1038,44 +981,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _disableBumpMap: boolean = false; - /** - * AKA Occlusion Texture in other nomenclature. - * @internal - */ - public _ambientTexture: Nullable = null; - - /** - * AKA Occlusion Texture Intensity in other nomenclature. - * @internal - */ - public _ambientTextureStrength: number = 1.0; - - /** - * Defines how much the AO map is occluding the analytical lights (point spot...). - * 1 means it completely occludes it - * 0 mean it has no impact - * @internal - */ - public _ambientTextureImpactOnAnalyticalLights: number = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; - - /** - * Stores the alpha values in a texture. - * @internal - */ - public _opacityTexture: Nullable = null; - /** * Stores the reflection values in a texture. * @internal */ public _reflectionTexture: Nullable = null; - /** - * Stores the emissive values in a texture. - * @internal - */ - public _emissiveTexture: Nullable = null; - /** * Specifies that only the A channel from _metallicReflectanceTexture should be used. * If false, both RGB and A channels will be used @@ -1323,11 +1234,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ private _renderTargets = new SmartArray(16); - /** - * Sets the global ambient color for the material used in lighting calculations. - */ - private _globalAmbientColor = new Color3(0, 0, 0); - /** * If set to true, no lighting calculations will be applied. */ @@ -1464,7 +1370,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._specularIor; this._baseMetalRoughTexture; this._geometryOpacity; + this._geometryOpacityTexture; this._emissionColor; + this._emissionTexture; + this._ambientOcclusionTexture; } /** @@ -1511,7 +1420,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return false; } - return this.geometryOpacity < 1.0 || this._opacityTexture != null || this._shouldUseAlphaFromAlbedoTexture(); + return this.geometryOpacity < 1.0 || this.geometryOpacityTexture != null || this._shouldUseAlphaFromAlbedoTexture(); } /** @@ -1536,13 +1445,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { * @returns whether or not there is a usable alpha channel for transparency. */ protected _hasAlphaChannel(): boolean { - return this._opacityTexture != null; + 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 diffuse and opacity), only clone it once and reuse it on the other channels. Default false. + * @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 */ @@ -1689,18 +1598,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { - if (!this._ambientTexture.isReadyOrNotBlocking()) { - return false; - } - } - - if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { - if (!this._opacityTexture.isReadyOrNotBlocking()) { - return false; - } - } - const reflectionTexture = this._getReflectionTexture(); if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { if (!reflectionTexture.isReadyOrNotBlocking()) { @@ -1724,12 +1621,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { - if (!this._emissiveTexture.isReadyOrNotBlocking()) { - return false; - } - } - if (engine.getCaps().standardDerivatives && this._bumpTexture && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) { // Bump texture cannot be not blocking. if (!this._bumpTexture.isReady()) { @@ -1825,22 +1716,14 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public override buildUniformLayout(): void { // Order is important ! const ubo = this._uniformBuffer; - ubo.addUniform("vAmbientInfos", 4); - ubo.addUniform("vOpacityInfos", 2); - ubo.addUniform("vEmissiveInfos", 2); ubo.addUniform("vLightmapInfos", 2); ubo.addUniform("vBumpInfos", 3); - ubo.addUniform("ambientMatrix", 16); - ubo.addUniform("opacityMatrix", 16); - ubo.addUniform("emissiveMatrix", 16); ubo.addUniform("lightmapMatrix", 16); ubo.addUniform("bumpMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); ubo.addUniform("vLightingIntensity", 4); ubo.addUniform("pointSize", 1); - // ubo.addUniform("vEmissiveColor", 3); - ubo.addUniform("vAmbientColor", 3); ubo.addUniform("vDebugMode", 2); @@ -1933,27 +1816,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { - ubo.updateFloat4( - "vAmbientInfos", - this._ambientTexture.coordinatesIndex, - this._ambientTexture.level, - this._ambientTextureStrength, - this._ambientTextureImpactOnAnalyticalLights - ); - BindTextureMatrix(this._ambientTexture, ubo, "ambient"); - } - - if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { - ubo.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level); - BindTextureMatrix(this._opacityTexture, ubo, "opacity"); - } - - if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { - ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); - BindTextureMatrix(this._emissiveTexture, ubo, "emissive"); - } - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level); BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); @@ -1978,8 +1840,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.updateFloat("pointSize", this.pointSize); } - // ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly); - Object.values(this._uniformsList).forEach((uniform) => { // If the property actually defines a uniform, update it. if (uniform.numComponents === 4) { @@ -2004,11 +1864,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { ubo.updateVector4("vLightingIntensity", this._lightingInfos); - // Colors - scene.ambientColor.multiplyToRef(this._ambientColor, this._globalAmbientColor); - - ubo.updateColor3("vAmbientColor", this._globalAmbientColor); - ubo.updateFloat2("vDebugMode", this.debugLimit, this.debugFactor); } @@ -2022,24 +1877,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { - ubo.setTexture("ambientSampler", this._ambientTexture); - } - - if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { - ubo.setTexture("opacitySampler", this._opacityTexture); - } - BindIBLSamplers(scene, defines, ubo, reflectionTexture, this.realTimeFiltering); if (defines.ENVIRONMENTBRDF) { ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); } - if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { - ubo.setTexture("emissiveSampler", this._emissiveTexture); - } - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { ubo.setTexture("lightmapSampler", this._lightmapTexture); } @@ -2116,22 +1959,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture && this._ambientTexture.animations && this._ambientTexture.animations.length > 0) { - results.push(this._ambientTexture); - } - - if (this._opacityTexture && this._opacityTexture.animations && this._opacityTexture.animations.length > 0) { - results.push(this._opacityTexture); - } - if (this._reflectionTexture && this._reflectionTexture.animations && this._reflectionTexture.animations.length > 0) { results.push(this._reflectionTexture); } - if (this._emissiveTexture && this._emissiveTexture.animations && this._emissiveTexture.animations.length > 0) { - results.push(this._emissiveTexture); - } - if (this._bumpTexture && this._bumpTexture.animations && this._bumpTexture.animations.length > 0) { results.push(this._bumpTexture); } @@ -2158,22 +1989,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture) { - activeTextures.push(this._ambientTexture); - } - - if (this._opacityTexture) { - activeTextures.push(this._opacityTexture); - } - if (this._reflectionTexture) { activeTextures.push(this._reflectionTexture); } - if (this._emissiveTexture) { - activeTextures.push(this._emissiveTexture); - } - if (this._bumpTexture) { activeTextures.push(this._bumpTexture); } @@ -2203,22 +2022,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture === texture) { - return true; - } - - if (this._opacityTexture === texture) { - return true; - } - if (this._reflectionTexture === texture) { return true; } - if (this._emissiveTexture === texture) { - return true; - } - if (this._bumpTexture === texture) { return true; } @@ -2258,10 +2065,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { sampler.value?.dispose(); } - this._ambientTexture?.dispose(); - this._opacityTexture?.dispose(); this._reflectionTexture?.dispose(); - this._emissiveTexture?.dispose(); this._bumpTexture?.dispose(); this._lightmapTexture?.dispose(); } @@ -2370,14 +2174,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { fallbacks.addFallback(fallbackRank++, "NORMAL"); } - if (defines.AMBIENT) { - fallbacks.addFallback(fallbackRank++, "AMBIENT"); - } - - if (defines.EMISSIVE) { - fallbacks.addFallback(fallbackRank++, "EMISSIVE"); - } - if (defines.VERTEXCOLOR) { fallbacks.addFallback(fallbackRank++, "VERTEXCOLOR"); } @@ -2424,30 +2220,16 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "viewProjection", "vEyePosition", "vLightsType", - "vAmbientColor", - "vMetallicReflectanceFactors", "visibility", "vFogInfos", "vFogColor", "pointSize", - "vAlbedoInfos", - "vAmbientInfos", - "vOpacityInfos", - "vEmissiveInfos", - "vMetallicReflectanceInfos", - "vReflectanceInfos", "vBumpInfos", "vLightmapInfos", "mBones", - "albedoMatrix", - "ambientMatrix", - "opacityMatrix", - "emissiveMatrix", "normalMatrix", "bumpMatrix", "lightmapMatrix", - "metallicReflectanceMatrix", - "reflectanceMatrix", "vLightingIntensity", "logarithmicDepthConstant", "vTangentSpaceParams", @@ -2464,11 +2246,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { const samplers = [ "reflectivitySampler", - "ambientSampler", - "emissiveSampler", "bumpSampler", "lightmapSampler", - "opacitySampler", "environmentBrdfSampler", "boneSampler", "metallicReflectanceSampler", @@ -2623,20 +2402,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) { - PrepareDefinesForMergedUV(this._ambientTexture, defines, "AMBIENT"); - defines.AMBIENTINGRAYSCALE = this._useAmbientInGrayScale; - } else { - defines.AMBIENT = false; - } - - if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) { - PrepareDefinesForMergedUV(this._opacityTexture, defines, "OPACITY"); - defines.OPACITYRGB = this._opacityTexture.getAlphaFromRGB; - } else { - defines.OPACITY = false; - } - const reflectionTexture = this._getReflectionTexture(); const useSHInFragment: boolean = this._forceIrradianceInFragment || @@ -2655,13 +2420,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines.LIGHTMAP = false; } - if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) { - PrepareDefinesForMergedUV(this._emissiveTexture, defines, "EMISSIVE"); - defines.GAMMAEMISSIVE = this._emissiveTexture.gammaSpace; - } else { - defines.EMISSIVE = false; - } - if (MaterialFlags.SpecularTextureEnabled) { if (this._baseMetalRoughTexture) { defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index 1d1cf2e74b2..c1157e90f43 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -23,21 +23,14 @@ layout(std140, column_major) uniform; // } uniform Material { - vec4 vAmbientInfos; - vec2 vOpacityInfos; - vec2 vEmissiveInfos; vec2 vLightmapInfos; vec3 vBumpInfos; - mat4 ambientMatrix; - mat4 opacityMatrix; - mat4 emissiveMatrix; mat4 lightmapMatrix; mat4 bumpMatrix; vec2 vTangentSpaceParams; vec4 vLightingIntensity; float pointSize; - vec3 vAmbientColor; vec2 vDebugMode; @@ -77,7 +70,7 @@ uniform Material { float vBaseDiffuseRoughness; vec4 vReflectanceInfo; vec4 vSpecularColor; - vec3 vEmissiveColor; + vec3 vEmissionColor; vec2 vBaseWeightInfos; mat4 baseWeightMatrix; @@ -85,12 +78,18 @@ uniform Material { mat4 baseColorMatrix; vec2 vBaseDiffuseRoughnessInfos; mat4 baseDiffuseRoughnessMatrix; - vec2 vBaseMetalRoughInfos; - mat4 baseMetalRoughMatrix; 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 }; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx index e0a0d3613df..aa96e0ca8cb 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -10,7 +10,6 @@ vec4 finalColor = vec4( finalRadianceScaled + #endif #endif - finalAmbient + finalDiffuse, alpha); @@ -26,7 +25,7 @@ vec4 finalColor = vec4( #endif // _____________________________ EmissiveLight _____________________________________ -finalColor.rgb += finalEmissive; +finalColor.rgb += finalEmission; #define CUSTOM_FRAGMENT_BEFORE_FOG diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index 4bbc1106acd..d317ba67432 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -8,12 +8,10 @@ uniform float vBaseDiffuseRoughness; // CUSTOM CONTROLS uniform vec4 vLightingIntensity; -uniform vec3 vEmissiveColor; +uniform vec3 vEmissionColor; uniform float visibility; -uniform vec3 vAmbientColor; - // Samplers #ifdef BASE_COLOR uniform vec2 vBaseColorInfos; @@ -27,8 +25,8 @@ uniform vec2 vBaseWeightInfos; uniform vec2 vBaseDiffuseRoughnessInfos; #endif -#ifdef AMBIENT -uniform vec4 vAmbientInfos; +#ifdef AMBIENT_OCCLUSION +uniform vec4 vAmbientOcclusionInfos; #endif #ifdef BUMP @@ -36,12 +34,12 @@ uniform vec3 vBumpInfos; uniform vec2 vTangentSpaceParams; #endif -#ifdef OPACITY -uniform vec2 vOpacityInfos; +#ifdef GEOMETRY_OPACITY +uniform vec2 vGeometryOpacityInfos; #endif -#ifdef EMISSIVE -uniform vec2 vEmissiveInfos; +#ifdef EMISSION +uniform vec2 vEmissionInfos; #endif #ifdef LIGHTMAP diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 673e42f5069..f9955dbdf73 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -1,14 +1,15 @@ #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_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) -#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) -#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough,_SAMPLERNAME_,baseMetalRough) -#include(_DEFINENAME_,METALLIC_REFLECTANCE,_VARYINGNAME_,MetallicReflectance,_SAMPLERNAME_,metallicReflectance) -#include(_DEFINENAME_,REFLECTANCE,_VARYINGNAME_,Reflectance,_SAMPLERNAME_,reflectance) +#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 diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx index c304218eb3e..4997164b647 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -5,7 +5,7 @@ uniform vec4 vEyePosition; mat4 viewProjectionR; #endif -#ifdef ALBEDO +#ifdef BASE_COLOR uniform vec2 vBaseColorInfos; uniform mat4 baseColorMatrix; #endif @@ -21,19 +21,19 @@ uniform mat4 baseDiffuseRoughnessMatrix; uniform vec2 vBaseDiffuseRoughnessInfos; #endif -#ifdef AMBIENT -uniform mat4 ambientMatrix; -uniform vec4 vAmbientInfos; +#ifdef GEOMETRY_OPACITY +uniform mat4 geometryOpacityMatrix; +uniform vec2 vGeometryOpacityInfos; #endif -#ifdef OPACITY -uniform mat4 opacityMatrix; -uniform vec2 vOpacityInfos; +#ifdef AMBIENT_OCCLUSION +uniform vec2 vAmbientOcclusionInfos; +uniform mat4 ambientOcclusionMatrix; #endif -#ifdef EMISSIVE -uniform vec2 vEmissiveInfos; -uniform mat4 emissiveMatrix; +#ifdef EMISSION +uniform vec2 vEmissionInfos; +uniform mat4 emissionMatrix; #endif #ifdef LIGHTMAP @@ -46,13 +46,14 @@ uniform vec2 vBaseMetalRoughInfos; uniform mat4 baseMetalRoughMatrix; #endif -#ifdef METALLIC_REFLECTANCE - uniform vec2 vMetallicReflectanceInfos; - uniform mat4 metallicReflectanceMatrix; +#ifdef SPECULAR_WEIGHT +uniform vec2 vSpecularWeightInfos; +uniform mat4 specularWeightMatrix; #endif -#ifdef REFLECTANCE - uniform vec2 vReflectanceInfos; - uniform mat4 reflectanceMatrix; + +#ifdef SPECULAR_COLOR +uniform vec2 vSpecularColorInfos; +uniform mat4 specularColorMatrix; #endif #ifdef BUMP @@ -72,97 +73,6 @@ uniform vec4 cameraInfo; uniform mat4 reflectionMatrix; #endif -// Clear Coat -#ifdef CLEARCOAT - #if defined(CLEARCOAT_TEXTURE) || defined(CLEARCOAT_TEXTURE_ROUGHNESS) - uniform vec4 vClearCoatInfos; - #endif - - #ifdef CLEARCOAT_TEXTURE - uniform mat4 clearCoatMatrix; - #endif - - #ifdef CLEARCOAT_TEXTURE_ROUGHNESS - uniform mat4 clearCoatRoughnessMatrix; - #endif - - #ifdef CLEARCOAT_BUMP - uniform vec2 vClearCoatBumpInfos; - uniform mat4 clearCoatBumpMatrix; - #endif - - #ifdef CLEARCOAT_TINT_TEXTURE - uniform vec2 vClearCoatTintInfos; - uniform mat4 clearCoatTintMatrix; - #endif -#endif - -// Iridescence -#ifdef IRIDESCENCE - #if defined(IRIDESCENCE_TEXTURE) || defined(IRIDESCENCE_THICKNESS_TEXTURE) - uniform vec4 vIridescenceInfos; - #endif - - #ifdef IRIDESCENCE_TEXTURE - uniform mat4 iridescenceMatrix; - #endif - - #ifdef IRIDESCENCE_THICKNESS_TEXTURE - uniform mat4 iridescenceThicknessMatrix; - #endif -#endif - -// Anisotropy -#ifdef ANISOTROPIC - #ifdef ANISOTROPIC_TEXTURE - uniform vec2 vAnisotropyInfos; - uniform mat4 anisotropyMatrix; - #endif -#endif - -// Sheen -#ifdef SHEEN - #if defined(SHEEN_TEXTURE) || defined(SHEEN_TEXTURE_ROUGHNESS) - uniform vec4 vSheenInfos; - #endif - - #ifdef SHEEN_TEXTURE - uniform mat4 sheenMatrix; - #endif - - #ifdef SHEEN_TEXTURE_ROUGHNESS - uniform mat4 sheenRoughnessMatrix; - #endif -#endif - -// Sub Surface -#ifdef SUBSURFACE - #ifdef SS_REFRACTION - uniform vec4 vRefractionInfos; - uniform mat4 refractionMatrix; - #endif - - #ifdef SS_THICKNESSANDMASK_TEXTURE - uniform vec2 vThicknessInfos; - uniform mat4 thicknessMatrix; - #endif - - #ifdef SS_REFRACTIONINTENSITY_TEXTURE - uniform vec2 vRefractionIntensityInfos; - uniform mat4 refractionIntensityMatrix; - #endif - - #ifdef SS_TRANSLUCENCYINTENSITY_TEXTURE - uniform vec2 vTranslucencyIntensityInfos; - uniform mat4 translucencyIntensityMatrix; - #endif - - #ifdef SS_TRANSLUCENCYCOLOR_TEXTURE - uniform vec2 vTranslucencyColorInfos; - uniform mat4 translucencyColorMatrix; - #endif -#endif - #ifdef NORMAL #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX) #ifdef USESPHERICALFROMREFLECTIONMAP diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 6ce8d8bde9f..32da1a6614d 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -62,7 +62,7 @@ precision highp float; #include #include -#include +#include #include #include @@ -148,14 +148,14 @@ void main(void) { // _____________________________ AO _______________________________ ambientOcclusionOutParams aoOut; -#ifdef AMBIENT - vec3 ambientOcclusionColorMap = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb; +#ifdef AMBIENT_OCCLUSION + vec3 ambientOcclusionFromTexture = texture2D(ambientOcclusionSampler, vAmbientOcclusionUV + uvOffset).rgb; #endif aoOut = ambientOcclusionBlock( - #ifdef AMBIENT - ambientOcclusionColorMap, - vAmbientInfos + #ifdef AMBIENT_OCCLUSION + ambientOcclusionFromTexture, + vAmbientOcclusionInfos #endif ); @@ -213,9 +213,9 @@ vec4 specularColor = vSpecularColor; #ifdef METALLIC_ROUGHNESS , vec3(vBaseMetalRoughInfos, 1.0f) , metallicRoughnessFromTexture - #endif - #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) - , aoOut.ambientOcclusionColor + #ifdef AOSTOREINMETALMAPRED + , aoOut.ambientOcclusionColor + #endif #endif #ifdef DETAIL , detailColor @@ -225,8 +225,6 @@ vec4 specularColor = vSpecularColor; float roughness = reflectivityOut.roughness; float diffuseRoughness = reflectivityOut.diffuseRoughness; - - // surfaceAlbedo = reflectivityOut.surfaceAlbedo; #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; @@ -235,7 +233,6 @@ vec4 specularColor = vSpecularColor; // _____________________________ Compute Geometry info _________________________________ #include - // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION reflectionOutParams reflectionOut; @@ -312,7 +309,31 @@ vec4 specularColor = vSpecularColor; #include #endif // !UNLIT - #include + // #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 diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 7836a4b20ee..1f3ffdf2f8c 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -36,16 +36,17 @@ attribute vec4 color; #include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,BaseColor) #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) -#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) -#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient) -#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) -#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) #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; @@ -215,16 +216,17 @@ void main(void) { #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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) - #include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_MATRIXNAME_,ambient,_INFONAME_,AmbientInfos.x) - #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) - #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) - #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.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 diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index be6feacd61c..a401a7e0a8d 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -1,18 +1,12 @@ -uniform vAmbientInfos: vec4f; -uniform vOpacityInfos: vec2f; -uniform vEmissiveInfos: vec2f; + uniform vLightmapInfos: vec2f; uniform vBumpInfos: vec3f; -uniform ambientMatrix: mat4x4f; -uniform opacityMatrix: mat4x4f; -uniform emissiveMatrix: mat4x4f; uniform lightmapMatrix: mat4x4f; uniform bumpMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; uniform vLightingIntensity: vec4f; uniform pointSize: f32; -uniform vAmbientColor: vec3f; uniform vDebugMode: vec2f; @@ -52,7 +46,7 @@ uniform vBaseColor: vec4f; uniform vBaseDiffuseRoughness: f32; uniform vReflectanceInfo: vec4f; uniform vSpecularColor: vec4f; -uniform vEmissiveColor: vec3f; +uniform vEmissionColor: vec3f; uniform vBaseWeightInfos: vec2f; uniform baseWeightMatrix: mat4x4f; @@ -60,12 +54,18 @@ uniform vBaseColorInfos: vec2f; uniform baseColorMatrix: mat4x4f; uniform vBaseDiffuseRoughnessInfos: vec2f; uniform baseDiffuseRoughnessMatrix: mat4x4f; -uniform vBaseMetalRoughInfos: vec2f; -uniform baseMetalRoughMatrix: 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 diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx index a56f7056b55..1f45834e4b8 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx @@ -10,7 +10,6 @@ var finalColor: vec4f = vec4f( finalRadianceScaled + #endif #endif - finalAmbient + finalDiffuse, alpha); @@ -26,7 +25,7 @@ var finalColor: vec4f = vec4f( #endif // _____________________________ EmissiveLight _____________________________________ -finalColor = vec4f(finalColor.rgb + finalEmissive, finalColor.a); +finalColor = vec4f(finalColor.rgb + finalEmission, finalColor.a); #define CUSTOM_FRAGMENT_BEFORE_FOG diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index dd80615a595..78bf8a3c071 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -1,14 +1,16 @@ #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_,AMBIENT,_VARYINGNAME_,Ambient,_SAMPLERNAME_,ambient) -#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_SAMPLERNAME_,opacity) -#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_SAMPLERNAME_,emissive) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_SAMPLERNAME_,lightmap) #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 diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index c7c5c09738d..3e29dd60f18 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include @@ -121,14 +121,14 @@ fn main(input: FragmentInputs) -> FragmentOutputs { // _____________________________ AO _______________________________ var aoOut: ambientOcclusionOutParams; -#ifdef AMBIENT - var ambientOcclusionColorMap: vec3f = textureSample(ambientSampler, ambientSamplerSampler, fragmentInputs.vAmbientUV + uvOffset).rgb; +#ifdef AMBIENT_OCCLUSION + var ambientOcclusionFromTexture: vec3f = textureSample(ambientOcclusionSampler, ambientOcclusionSamplerSampler, fragmentInputs.vAmbientOcclusionUV + uvOffset).rgb; #endif aoOut = ambientOcclusionBlock( - #ifdef AMBIENT - ambientOcclusionColorMap, - uniforms.vAmbientInfos + #ifdef AMBIENT_OCCLUSION + ambientOcclusionFromTexture, + uniforms.vAmbientOcclusionInfos #endif ); @@ -286,7 +286,29 @@ var specularColor: vec4f = uniforms.vSpecularColor; #include #endif // UNLIT - #include + // _____________________________ 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 diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 10fc816f04f..8daa3da7b79 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -32,16 +32,17 @@ attribute color: vec4f; #include(_DEFINENAME_,BASE_COLOR,_VARYINGNAME_,Albedo) #include(_DEFINENAME_,BASE_WEIGHT,_VARYINGNAME_,BaseWeight) #include(_DEFINENAME_,BASE_DIFFUSE_ROUGHNESS,_VARYINGNAME_,BaseDiffuseRoughness) -#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) -#include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient) -#include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity) -#include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) #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; @@ -202,17 +203,18 @@ fn main(input : VertexInputs) -> FragmentInputs { #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_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) - #include(_DEFINENAME_,AMBIENT,_VARYINGNAME_,Ambient,_MATRIXNAME_,ambient,_INFONAME_,AmbientInfos.x) - #include(_DEFINENAME_,OPACITY,_VARYINGNAME_,Opacity,_MATRIXNAME_,opacity,_INFONAME_,OpacityInfos.x) - #include(_DEFINENAME_,EMISSIVE,_VARYINGNAME_,Emissive,_MATRIXNAME_,emissive,_INFONAME_,EmissiveInfos.x) - #include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap,_MATRIXNAME_,lightmap,_INFONAME_,LightmapInfos.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 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 de92d12c984..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 @@ -68,12 +68,15 @@ export class MSFT_sRGBFactors implements IGLTFLoaderExtension { 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.reflectivityColor, useExactSrgbConversions); + (babylonMaterial as PBRMaterial).reflectivityColor.toLinearSpaceToRef((babylonMaterial as PBRMaterial).reflectivityColor, useExactSrgbConversions); } } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 9b91b05253d..53bb821a4d5 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -2267,8 +2267,10 @@ export class GLTFLoader implements IGLTFLoader { // 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; + 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; @@ -2361,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; } } @@ -2380,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; + } + }); } /** From c3d174fa4f84c5d707e4a3652f1ce44e890241ef Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 21 Jul 2025 14:55:17 -0700 Subject: [PATCH 24/45] Add geometry_normal to OpenPBR material --- .../core/src/Materials/PBR/openPbrMaterial.ts | 108 ++++------------- .../src/Rendering/geometryBufferRenderer.ts | 12 +- .../ShadersInclude/openPbrUboDeclaration.fx | 5 +- .../openpbrBlockAmbientOcclusion.fx | 30 +++++ .../openpbrBlockGeometryInfo.fx | 35 ++++++ .../ShadersInclude/openpbrBlockReflectance.fx | 2 +- .../openpbrFragmentDeclaration.fx | 4 +- .../openpbrFragmentSamplersDeclaration.fx | 34 ------ .../openpbrNormalMapFragment.fx | 77 +++++++++++++ .../openpbrNormalMapFragment.js | 63 ++++++++++ .../openpbrNormalMapFragment.js.map | 1 + .../openpbrNormalMapFragmentFunctions.fx | 79 +++++++++++++ .../openpbrNormalMapFragmentFunctions.js | 42 +++++++ .../openpbrNormalMapFragmentFunctions.js.map | 1 + .../openpbrNormalMapFragmentMainFunctions.fx | 108 +++++++++++++++++ .../openpbrNormalMapFragmentMainFunctions.js | 72 ++++++++++++ ...enpbrNormalMapFragmentMainFunctions.js.map | 1 + .../ShadersInclude/openpbrNormalMapVertex.fx | 8 ++ .../ShadersInclude/openpbrNormalMapVertex.js | 16 +++ .../openpbrNormalMapVertex.js.map | 1 + .../openpbrNormalMapVertexDeclaration.fx | 5 + .../openpbrNormalMapVertexDeclaration.js | 16 +++ .../openpbrNormalMapVertexDeclaration.js.map | 1 + .../openpbrVertexDeclaration.fx | 6 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 10 +- .../dev/core/src/Shaders/openpbr.vertex.fx | 9 +- .../ShadersInclude/openPbrUboDeclaration.fx | 5 +- .../openpbrBlockAmbientOcclusion.fx | 31 +++++ .../openpbrBlockGeometryInfo.fx | 35 ++++++ .../ShadersInclude/openpbrBlockReflectance.fx | 2 +- .../openpbrNormalMapFragment.fx | 77 +++++++++++++ .../openpbrNormalMapFragment.js | 63 ++++++++++ .../openpbrNormalMapFragment.js.map | 1 + .../openpbrNormalMapFragmentFunctions.fx | 79 +++++++++++++ .../openpbrNormalMapFragmentFunctions.js | 42 +++++++ .../openpbrNormalMapFragmentFunctions.js.map | 1 + .../openpbrNormalMapFragmentMainFunctions.fx | 109 ++++++++++++++++++ .../openpbrNormalMapFragmentMainFunctions.js | 51 ++++++++ ...enpbrNormalMapFragmentMainFunctions.js.map | 1 + .../ShadersInclude/openpbrNormalMapVertex.fx | 11 ++ .../openpbrNormalMapVertexDeclaration.fx | 7 ++ .../core/src/ShadersWGSL/openpbr.fragment.fx | 8 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 8 +- .../pbrMaterialPropertyGridComponent.tsx | 78 +++++++------ .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 18 ++- 45 files changed, 1176 insertions(+), 197 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertex.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertexDeclaration.fx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index d6ca912183a..77bfe70a1ad 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -245,8 +245,6 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public NORMAL = false; public TANGENT = false; - public BUMP = false; - public BUMPDIRECTUV = 0; public OBJECTSPACE_NORMALMAP = false; public PARALLAX = false; public PARALLAX_RHS = false; @@ -564,6 +562,15 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _baseMetalRoughTexture: Sampler = new Sampler("base_metalness_specular_roughness", "baseMetalRough", "METALLIC_ROUGHNESS"); + /** + * Defines the normal of the material's geometry. + * See OpenPBR's specs for geometry_normal + */ + public geometryNormalTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "geometryNormalTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _geometryNormalTexture: Sampler = new Sampler("geometry_normal", "geometryNormal", "GEOMETRY_NORMAL"); + /** * Defines the opacity of the material's geometry. * See OpenPBR's specs for geometry_opacity @@ -637,13 +644,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @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. */ @@ -658,13 +658,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @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. */ @@ -791,14 +784,14 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public useObjectSpaceNormalMap = false; /** - * Allows using the bump map in parallax mode. + * Allows using the normal map in parallax mode. */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") public useParallax = false; /** - * Allows using the bump map in parallax occlusion mode. + * Allows using the normal map in parallax occlusion mode. */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") @@ -819,7 +812,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public disableLighting = false; /** - * Force the shader to compute irradiance in the fragment shader in order to take bump in account. + * Force the shader to compute irradiance in the fragment shader in order to take normal mapping into account. */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") @@ -890,7 +883,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { /** * 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. + * It also prefilter the roughness map based on the normalmap values. */ @serialize() @expandToProperty("_markAllSubMeshesAsTexturesDirty") @@ -975,12 +968,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ 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 @@ -994,12 +981,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ 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 @@ -1103,13 +1084,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public _useObjectSpaceNormalMap = false; /** - * Allows using the bump map in parallax mode. + * Allows using the normal map in parallax mode. * @internal */ public _useParallax = false; /** - * Allows using the bump map in parallax occlusion mode. + * Allows using the normal map in parallax occlusion mode. * @internal */ public _useParallaxOcclusion = false; @@ -1179,7 +1160,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public _environmentBRDFTexture: Nullable = null; /** - * Force the shader to compute irradiance in the fragment shader in order to take bump in account. + * Force the shader to compute irradiance in the fragment shader in order to take normal mapping into account. * @internal */ public _forceIrradianceInFragment = false; @@ -1224,7 +1205,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { /** * 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. + * It also prefilter the roughness map based on the normalmap values. * @internal */ public _enableSpecularAntiAliasing = false; @@ -1369,6 +1350,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._specularRoughness; this._specularIor; this._baseMetalRoughTexture; + this._geometryNormalTexture; this._geometryOpacity; this._geometryOpacityTexture; this._emissionColor; @@ -1621,13 +1603,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - 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()) { @@ -1717,9 +1692,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // 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); @@ -1821,10 +1794,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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 (this.geometryNormalTexture) { if (scene._mirroredCameraPosition) { ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0); } else { @@ -1886,10 +1856,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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 @@ -1963,10 +1929,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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); } @@ -1993,10 +1955,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { activeTextures.push(this._reflectionTexture); } - if (this._bumpTexture) { - activeTextures.push(this._bumpTexture); - } - if (this._lightmapTexture) { activeTextures.push(this._lightmapTexture); } @@ -2026,10 +1984,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return true; } - if (this._bumpTexture === texture) { - return true; - } - if (this._lightmapTexture === texture) { return true; } @@ -2066,7 +2020,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } this._reflectionTexture?.dispose(); - this._bumpTexture?.dispose(); this._lightmapTexture?.dispose(); } @@ -2148,10 +2101,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { fallbacks.addFallback(fallbackRank++, "TANGENT"); } - if (defines.BUMP) { - fallbacks.addFallback(fallbackRank++, "BUMP"); - } - fallbackRank = HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights, fallbackRank++); if (defines.SPECULARTERM) { @@ -2224,11 +2173,9 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vFogInfos", "vFogColor", "pointSize", - "vBumpInfos", "vLightmapInfos", "mBones", "normalMatrix", - "bumpMatrix", "lightmapMatrix", "vLightingIntensity", "logarithmicDepthConstant", @@ -2245,13 +2192,9 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } const samplers = [ - "reflectivitySampler", - "bumpSampler", "lightmapSampler", "environmentBrdfSampler", "boneSampler", - "metallicReflectanceSampler", - "reflectanceSampler", "morphTargets", "oitDepthSampler", "oitFrontColorSampler", @@ -2378,13 +2321,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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) { @@ -2428,9 +2364,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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.geometryNormalTexture) { if (this._useParallax && this.baseColorTexture && MaterialFlags.DiffuseTextureEnabled) { defines.PARALLAX = true; defines.PARALLAX_RHS = scene.useRightHandedSystem; @@ -2438,10 +2372,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } else { defines.PARALLAX = false; } - defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap; } else { - defines.BUMP = false; defines.PARALLAX = false; defines.PARALLAX_RHS = false; defines.PARALLAXOCCLUSION = false; diff --git a/packages/dev/core/src/Rendering/geometryBufferRenderer.ts b/packages/dev/core/src/Rendering/geometryBufferRenderer.ts index b735be41353..fbe6268b272 100644 --- a/packages/dev/core/src/Rendering/geometryBufferRenderer.ts +++ b/packages/dev/core/src/Rendering/geometryBufferRenderer.ts @@ -568,8 +568,8 @@ export class GeometryBufferRenderer { } // Normal map texture - if ((material.bumpTexture || material.normalTexture) && MaterialFlags.BumpTextureEnabled) { - const texture = material.bumpTexture || material.normalTexture; + if ((material.bumpTexture || material.normalTexture || material.geometryNormalTexture) && MaterialFlags.BumpTextureEnabled) { + const texture = material.bumpTexture || material.normalTexture || material.geometryNormalTexture; defines.push("#define BUMP"); defines.push(`#define BUMP_UV${texture.coordinatesIndex + 1}`); needUv = true; @@ -1110,8 +1110,12 @@ export class GeometryBufferRenderer { } // Bump - if ((material.bumpTexture || material.normalTexture) && scene.getEngine().getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled) { - const texture = material.bumpTexture || material.normalTexture; + if ( + (material.bumpTexture || material.normalTexture || material.geometryNormalTexture) && + scene.getEngine().getCaps().standardDerivatives && + MaterialFlags.BumpTextureEnabled + ) { + const texture = material.bumpTexture || material.normalTexture || material.geometryNormalTexture; effect.setFloat3("vBumpInfos", texture.coordinatesIndex, 1.0 / texture.level, material.parallaxScaleBias); effect.setMatrix("bumpMatrix", texture.getTextureMatrix()); effect.setTexture("bumpSampler", texture); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index c1157e90f43..f889a36129f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -24,10 +24,7 @@ layout(std140, column_major) uniform; uniform Material { vec2 vLightmapInfos; - vec3 vBumpInfos; - mat4 lightmapMatrix; - mat4 bumpMatrix; vec2 vTangentSpaceParams; vec4 vLightingIntensity; float pointSize; @@ -84,6 +81,8 @@ uniform Material { mat4 specularColorMatrix; vec2 vBaseMetalRoughInfos; mat4 baseMetalRoughMatrix; + vec2 vGeometryNormalInfos; + mat4 geometryNormalMatrix; vec2 vGeometryOpacityInfos; mat4 geometryOpacityMatrix; vec2 vEmissionInfos; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx new file mode 100644 index 00000000000..c0a25e633b3 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx @@ -0,0 +1,30 @@ +struct ambientOcclusionOutParams +{ + vec3 ambientOcclusionColor; +#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) + vec3 ambientOcclusionColorMap; +#endif +}; + +ambientOcclusionOutParams ambientOcclusionBlock( +#ifdef AMBIENT_OCCLUSION + in vec3 ambientOcclusionFromTexture, + in vec2 ambientOcclusionInfos +#endif +) +{ + ambientOcclusionOutParams outParams; + vec3 ambientOcclusionColor = vec3(1., 1., 1.); + + #ifdef AMBIENT_OCCLUSION + ambientOcclusionColor = vec3(ambientOcclusionFromTexture.r * ambientOcclusionInfos.y); + + #if DEBUGMODE > 0 + outParams.ambientOcclusionColorMap = ambientOcclusionFromTexture; + #endif + #endif + + outParams.ambientOcclusionColor = ambientOcclusionColor; + + return outParams; +} diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx new file mode 100644 index 00000000000..6cdf2244cfd --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx @@ -0,0 +1,35 @@ +float NdotVUnclamped = dot(normalW, viewDirectionW); +// The order 1886 page 3. +float NdotV = absEps(NdotVUnclamped); +float alphaG = convertRoughnessToAverageSlope(roughness); +vec2 AARoughnessFactors = getAARoughnessFactors(normalW.xyz); + +#ifdef SPECULARAA + // Adapt linear roughness (alphaG) to geometric curvature of the current pixel. + alphaG += AARoughnessFactors.y; +#endif + +#if defined(ENVIRONMENTBRDF) + // BRDF Lookup + vec3 environmentBrdf = getBRDFLookup(NdotV, roughness); +#endif + +#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + #ifdef RADIANCEOCCLUSION + #ifdef AMBIENTINGRAYSCALE + float ambientMonochrome = aoOut.ambientOcclusionColor.r; + #else + float ambientMonochrome = getLuminance(aoOut.ambientOcclusionColor); + #endif + + float seo = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped); + #endif + + #ifdef HORIZONOCCLUSION + #ifdef GEOMETRY_NORMAL + #ifdef REFLECTIONMAP_3D + float eho = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); + #endif + #endif + #endif +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx index af4db665973..d41591fee1f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx @@ -23,7 +23,7 @@ #endif #ifdef HORIZONOCCLUSION - #ifdef BUMP + #ifdef GEOMETRY_NORMAL #ifdef REFLECTIONMAP_3D colorSpecularEnvironmentReflectance *= eho; #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index d317ba67432..762c207a42b 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -29,8 +29,8 @@ uniform vec2 vBaseDiffuseRoughnessInfos; uniform vec4 vAmbientOcclusionInfos; #endif -#ifdef BUMP -uniform vec3 vBumpInfos; +#ifdef GEOMETRY_NORMAL +uniform vec2 vGeometryNormalInfos; uniform vec2 vTangentSpaceParams; #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index f9955dbdf73..b44f1d73601 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -58,40 +58,6 @@ 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/openpbrNormalMapFragment.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx new file mode 100644 index 00000000000..f0b780f1c82 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx @@ -0,0 +1,77 @@ +vec2 uvOffset = vec2(0.0, 0.0); + +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) + #ifdef NORMALXYSCALE + float normalScale = 1.0; + #elif defined(GEOMETRY_NORMAL) + float normalScale = vGeometryNormalInfos.y; + #else + float normalScale = 1.0; + #endif + + #if defined(TANGENT) && defined(NORMAL) + mat3 TBN = vTBN; + #elif defined(GEOMETRY_NORMAL) + // flip the uv for the backface + vec2 TBNUV = gl_FrontFacing ? vGeometryNormalUV : -vGeometryNormalUV; + mat3 TBN = cotangent_frame(normalW * normalScale, vPositionW, TBNUV, vTangentSpaceParams); + #else + // flip the uv for the backface + vec2 TBNUV = gl_FrontFacing ? vDetailUV : -vDetailUV; + mat3 TBN = cotangent_frame(normalW * normalScale, vPositionW, TBNUV, vec2(1., 1.)); + #endif +#elif defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + mat3 TBN = vTBN; + #else + // flip the uv for the backface + vec2 TBNUV = gl_FrontFacing ? vMainUV1 : -vMainUV1; + mat3 TBN = cotangent_frame(normalW, vPositionW, TBNUV, vec2(1., 1.)); + #endif +#endif + +#ifdef PARALLAX + mat3 invTBN = transposeMat3(TBN); + + #ifdef PARALLAXOCCLUSION + // TODO: Implement parallax occlusion scale + // uvOffset = parallaxOcclusion(invTBN * -viewDirectionW, invTBN * normalW, vGeometryNormalUV, vGeometryNormalInfos.z); + #else + // uvOffset = parallaxOffset(invTBN * viewDirectionW, vGeometryNormalInfos.z); + #endif +#endif + +#ifdef DETAIL + vec4 detailColor = texture2D(detailSampler, vDetailUV + uvOffset); + vec2 detailNormalRG = detailColor.wy * 2.0 - 1.0; + float detailNormalB = sqrt(1. - saturate(dot(detailNormalRG, detailNormalRG))); + vec3 detailNormal = vec3(detailNormalRG, detailNormalB); +#endif + +#ifdef GEOMETRY_NORMAL + #ifdef OBJECTSPACE_NORMALMAP + + #define CUSTOM_FRAGMENT_BUMP_FRAGMENT + + normalW = normalize(texture2D(geometryNormalSampler, vGeometryNormalUV).xyz * 2.0 - 1.0); + normalW = normalize(mat3(normalMatrix) * normalW); + #elif !defined(DETAIL) + normalW = perturbNormal(TBN, texture2D(geometryNormalSampler, vGeometryNormalUV + uvOffset).xyz, vGeometryNormalInfos.y); + #else + vec3 sampledNormal = texture2D(geometryNormalSampler, vGeometryNormalUV + uvOffset).xyz * 2.0 - 1.0; + // Reference for normal blending: https://blog.selfshadow.com/publications/blending-in-detail/ + #if DETAIL_NORMALBLENDMETHOD == 0 // whiteout + detailNormal.xy *= vDetailInfos.z; + vec3 blendedNormal = normalize(vec3(sampledNormal.xy + detailNormal.xy, sampledNormal.z * detailNormal.z)); + #elif DETAIL_NORMALBLENDMETHOD == 1 // RNM + detailNormal.xy *= vDetailInfos.z; + sampledNormal += vec3(0.0, 0.0, 1.0); + detailNormal *= vec3(-1.0, -1.0, 1.0); + vec3 blendedNormal = sampledNormal * dot(sampledNormal, detailNormal) / sampledNormal.z - detailNormal; + #endif + normalW = perturbNormalBase(TBN, blendedNormal, vGeometryNormalInfos.y); + #endif +#elif defined(DETAIL) + detailNormal.xy *= vDetailInfos.z; + normalW = perturbNormalBase(TBN, detailNormal, vDetailInfos.z); +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js new file mode 100644 index 00000000000..779073df38d --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js @@ -0,0 +1,63 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapFragment"; +const shader = `vec2 uvOffset=vec2(0.0,0.0); +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) +#ifdef NORMALXYSCALE +float normalScale=1.0; +#elif defined(GEOMETRY_NORMAL) +float normalScale=vGeometryNormalInfos.y; +#else +float normalScale=1.0; +#endif +#if defined(TANGENT) && defined(NORMAL) +mat3 TBN=vTBN; +#elif defined(GEOMETRY_NORMAL) +vec2 TBNUV=gl_FrontFacing ? vGeometryNormalUV : -vGeometryNormalUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vTangentSpaceParams); +#else +vec2 TBNUV=gl_FrontFacing ? vDetailUV : -vDetailUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vec2(1.,1.)); +#endif +#elif defined(ANISOTROPIC) +#if defined(TANGENT) && defined(NORMAL) +mat3 TBN=vTBN; +#else +vec2 TBNUV=gl_FrontFacing ? vMainUV1 : -vMainUV1;mat3 TBN=cotangent_frame(normalW,vPositionW,TBNUV,vec2(1.,1.)); +#endif +#endif +#ifdef PARALLAX +mat3 invTBN=transposeMat3(TBN); +#ifdef PARALLAXOCCLUSION +uvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,vGeometryNormalUV,vGeometryNormalInfos.z); +#else +uvOffset=parallaxOffset(invTBN*viewDirectionW,vGeometryNormalInfos.z); +#endif +#endif +#ifdef DETAIL +vec4 detailColor=texture2D(detailSampler,vDetailUV+uvOffset);vec2 detailNormalRG=detailColor.wy*2.0-1.0;float detailNormalB=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));vec3 detailNormal=vec3(detailNormalRG,detailNormalB); +#endif +#ifdef GEOMETRY_NORMAL +#ifdef OBJECTSPACE_NORMALMAP +#define CUSTOM_FRAGMENT_BUMP_FRAGMENT +normalW=normalize(texture2D(geometryNormalSampler,vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3(normalMatrix)*normalW); +#elif !defined(DETAIL) +normalW=perturbNormal(TBN,texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz,vGeometryNormalInfos.y); +#else +vec3 bumpNormal=texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz*2.0-1.0; +#if DETAIL_NORMALBLENDMETHOD==0 +detailNormal.xy*=vDetailInfos.z;vec3 blendedNormal=normalize(vec3(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z)); +#elif DETAIL_NORMALBLENDMETHOD==1 +detailNormal.xy*=vDetailInfos.z;bumpNormal+=vec3(0.0,0.0,1.0);detailNormal*=vec3(-1.0,-1.0,1.0);vec3 blendedNormal=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal; +#endif +normalW=perturbNormalBase(TBN,blendedNormal,vGeometryNormalInfos.y); +#endif +#elif defined(DETAIL) +detailNormal.xy*=vDetailInfos.z;normalW=perturbNormalBase(TBN,detailNormal,vDetailInfos.z); +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStore[name]) { + ShaderStore.IncludesShadersStore[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragment = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragment.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map new file mode 100644 index 00000000000..59012042574 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragment.js","sourceRoot":"","sources":["openpbrNormalMapFragment.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,0BAA0B,CAAC;AACxC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragment\";\nconst shader = `vec2 uvOffset=vec2(0.0,0.0);\n#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL)\n#ifdef NORMALXYSCALE\nfloat normalScale=1.0;\n#elif defined(GEOMETRY_NORMAL)\nfloat normalScale=vGeometryNormalInfos.y;\n#else\nfloat normalScale=1.0;\n#endif\n#if defined(TANGENT) && defined(NORMAL)\nmat3 TBN=vTBN;\n#elif defined(GEOMETRY_NORMAL)\nvec2 TBNUV=gl_FrontFacing ? vGeometryNormalUV : -vGeometryNormalUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vTangentSpaceParams);\n#else\nvec2 TBNUV=gl_FrontFacing ? vDetailUV : -vDetailUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vec2(1.,1.));\n#endif\n#elif defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nmat3 TBN=vTBN;\n#else\nvec2 TBNUV=gl_FrontFacing ? vMainUV1 : -vMainUV1;mat3 TBN=cotangent_frame(normalW,vPositionW,TBNUV,vec2(1.,1.));\n#endif\n#endif\n#ifdef PARALLAX\nmat3 invTBN=transposeMat3(TBN);\n#ifdef PARALLAXOCCLUSION\nuvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,vGeometryNormalUV,vGeometryNormalInfos.z);\n#else\nuvOffset=parallaxOffset(invTBN*viewDirectionW,vGeometryNormalInfos.z);\n#endif\n#endif\n#ifdef DETAIL\nvec4 detailColor=texture2D(detailSampler,vDetailUV+uvOffset);vec2 detailNormalRG=detailColor.wy*2.0-1.0;float detailNormalB=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));vec3 detailNormal=vec3(detailNormalRG,detailNormalB);\n#endif\n#ifdef GEOMETRY_NORMAL\n#ifdef OBJECTSPACE_NORMALMAP\n#define CUSTOM_FRAGMENT_BUMP_FRAGMENT\nnormalW=normalize(texture2D(geometryNormalSampler,vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3(normalMatrix)*normalW);\n#elif !defined(DETAIL)\nnormalW=perturbNormal(TBN,texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz,vGeometryNormalInfos.y);\n#else\nvec3 bumpNormal=texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz*2.0-1.0;\n#if DETAIL_NORMALBLENDMETHOD==0 \ndetailNormal.xy*=vDetailInfos.z;vec3 blendedNormal=normalize(vec3(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z));\n#elif DETAIL_NORMALBLENDMETHOD==1 \ndetailNormal.xy*=vDetailInfos.z;bumpNormal+=vec3(0.0,0.0,1.0);detailNormal*=vec3(-1.0,-1.0,1.0);vec3 blendedNormal=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal;\n#endif\nnormalW=perturbNormalBase(TBN,blendedNormal,vGeometryNormalInfos.y);\n#endif\n#elif defined(DETAIL)\ndetailNormal.xy*=vDetailInfos.z;normalW=perturbNormalBase(TBN,detailNormal,vDetailInfos.z);\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragment = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx new file mode 100644 index 00000000000..e9743f1c3a4 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx @@ -0,0 +1,79 @@ +#if defined(GEOMETRY_NORMAL) + #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) +#endif + +#if defined(DETAIL) + #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) +#endif + +#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) + const float minSamples = 4.; + const float maxSamples = 15.; + const int iMaxSamples = 15; + + // http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262 + vec2 parallaxOcclusion(vec3 vViewDirCoT, vec3 vNormalCoT, vec2 texCoord, float parallaxScale) { + + float parallaxLimit = length(vViewDirCoT.xy) / vViewDirCoT.z; + parallaxLimit *= parallaxScale; + vec2 vOffsetDir = normalize(vViewDirCoT.xy); + vec2 vMaxOffset = vOffsetDir * parallaxLimit; + float numSamples = maxSamples + (dot(vViewDirCoT, vNormalCoT) * (minSamples - maxSamples)); + float stepSize = 1.0 / numSamples; + + // Initialize the starting view ray height and the texture offsets. + float currRayHeight = 1.0; + vec2 vCurrOffset = vec2(0, 0); + vec2 vLastOffset = vec2(0, 0); + + float lastSampledHeight = 1.0; + float currSampledHeight = 1.0; + + bool keepWorking = true; + for (int i = 0; i < iMaxSamples; i++) + { + currSampledHeight = texture2D(geometryNormalSampler, texCoord + vCurrOffset).w; + + // Test if the view ray has intersected the surface. + if (!keepWorking) + { + // do nothing + } + else if (currSampledHeight > currRayHeight) + { + float delta1 = currSampledHeight - currRayHeight; + float delta2 = (currRayHeight + stepSize) - lastSampledHeight; + float ratio = delta1 / (delta1 + delta2); + vCurrOffset = (ratio)* vLastOffset + (1.0 - ratio) * vCurrOffset; + + keepWorking = false; + } + else + { + currRayHeight -= stepSize; + vLastOffset = vCurrOffset; + #ifdef PARALLAX_RHS + vCurrOffset -= stepSize * vMaxOffset; + #else + vCurrOffset += stepSize * vMaxOffset; + #endif + + lastSampledHeight = currSampledHeight; + } + } + + return vCurrOffset; + } + + vec2 parallaxOffset(vec3 viewDir, float heightScale) + { + // calculate amount of offset for Parallax Mapping With Offset Limiting + float height = texture2D(geometryNormalSampler, vGeometryNormalUV).w; + vec2 texCoordOffset = heightScale * viewDir.xy * height; + #ifdef PARALLAX_RHS + return texCoordOffset; + #else + return -texCoordOffset; + #endif + } +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js new file mode 100644 index 00000000000..b1cfd4b690e --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js @@ -0,0 +1,42 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +import "./samplerFragmentDeclaration"; +const name = "openpbrNormalMapFragmentFunctions"; +const shader = `#if defined(GEOMETRY_NORMAL) +#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) +#endif +#if defined(DETAIL) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) +#endif +#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) +const float minSamples=4.;const float maxSamples=15.;const int iMaxSamples=15;vec2 parallaxOcclusion(vec3 vViewDirCoT,vec3 vNormalCoT,vec2 texCoord,float parallaxScale) {float parallaxLimit=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;vec2 vOffsetDir=normalize(vViewDirCoT.xy);vec2 vMaxOffset=vOffsetDir*parallaxLimit;float numSamples=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));float stepSize=1.0/numSamples;float currRayHeight=1.0;vec2 vCurrOffset=vec2(0,0);vec2 vLastOffset=vec2(0,0);float lastSampledHeight=1.0;float currSampledHeight=1.0;bool keepWorking=true;for (int i=0; icurrRayHeight) +{float delta1=currSampledHeight-currRayHeight;float delta2=(currRayHeight+stepSize)-lastSampledHeight;float ratio=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;} +else +{currRayHeight-=stepSize;vLastOffset=vCurrOffset; +#ifdef PARALLAX_RHS +vCurrOffset-=stepSize*vMaxOffset; +#else +vCurrOffset+=stepSize*vMaxOffset; +#endif +lastSampledHeight=currSampledHeight;}} +return vCurrOffset;} +vec2 parallaxOffset(vec3 viewDir,float heightScale) +{float height=texture2D(geometryNormalSampler,vGeometryNormalUV).w;vec2 texCoordOffset=heightScale*viewDir.xy*height; +#ifdef PARALLAX_RHS +return texCoordOffset; +#else +return -texCoordOffset; +#endif +} +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStore[name]) { + ShaderStore.IncludesShadersStore[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragmentFunctions = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragmentFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map new file mode 100644 index 00000000000..7bb46666b4c --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragmentFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,8BAA8B,CAAC;AAEtC,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\nimport \"./samplerFragmentDeclaration\";\n\nconst name = \"openpbrNormalMapFragmentFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL)\n#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal)\n#endif\n#if defined(DETAIL)\n#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail)\n#endif\n#if defined(GEOMETRY_NORMAL) && defined(PARALLAX)\nconst float minSamples=4.;const float maxSamples=15.;const int iMaxSamples=15;vec2 parallaxOcclusion(vec3 vViewDirCoT,vec3 vNormalCoT,vec2 texCoord,float parallaxScale) {float parallaxLimit=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;vec2 vOffsetDir=normalize(vViewDirCoT.xy);vec2 vMaxOffset=vOffsetDir*parallaxLimit;float numSamples=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));float stepSize=1.0/numSamples;float currRayHeight=1.0;vec2 vCurrOffset=vec2(0,0);vec2 vLastOffset=vec2(0,0);float lastSampledHeight=1.0;float currSampledHeight=1.0;bool keepWorking=true;for (int i=0; icurrRayHeight)\n{float delta1=currSampledHeight-currRayHeight;float delta2=(currRayHeight+stepSize)-lastSampledHeight;float ratio=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;}\nelse\n{currRayHeight-=stepSize;vLastOffset=vCurrOffset;\n#ifdef PARALLAX_RHS\nvCurrOffset-=stepSize*vMaxOffset;\n#else\nvCurrOffset+=stepSize*vMaxOffset;\n#endif\nlastSampledHeight=currSampledHeight;}}\nreturn vCurrOffset;}\nvec2 parallaxOffset(vec3 viewDir,float heightScale)\n{float height=texture2D(geometryNormalSampler,vGeometryNormalUV).w;vec2 texCoordOffset=heightScale*viewDir.xy*height;\n#ifdef PARALLAX_RHS\nreturn texCoordOffset;\n#else\nreturn -texCoordOffset;\n#endif\n}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentFunctions = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx new file mode 100644 index 00000000000..d1fb7b6ef61 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx @@ -0,0 +1,108 @@ +#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) + #if defined(TANGENT) && defined(NORMAL) + varying mat3 vTBN; + #endif + + #ifdef OBJECTSPACE_NORMALMAP + uniform mat4 normalMatrix; + + #if defined(WEBGL2) || defined(WEBGPU) + mat4 toNormalMatrix(mat4 wMatrix) + { + mat4 ret = inverse(wMatrix); + ret = transpose(ret); + ret[0][3] = 0.; + ret[1][3] = 0.; + ret[2][3] = 0.; + ret[3] = vec4(0., 0., 0., 1.); + return ret; + } + #else + mat4 toNormalMatrix(mat4 m) + { + float + a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3], + a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3], + a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3], + a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + mat4 mi = mat4( + a11 * b11 - a12 * b10 + a13 * b09, + a02 * b10 - a01 * b11 - a03 * b09, + a31 * b05 - a32 * b04 + a33 * b03, + a22 * b04 - a21 * b05 - a23 * b03, + a12 * b08 - a10 * b11 - a13 * b07, + a00 * b11 - a02 * b08 + a03 * b07, + a32 * b02 - a30 * b05 - a33 * b01, + a20 * b05 - a22 * b02 + a23 * b01, + a10 * b10 - a11 * b08 + a13 * b06, + a01 * b08 - a00 * b10 - a03 * b06, + a30 * b04 - a31 * b02 + a33 * b00, + a21 * b02 - a20 * b04 - a23 * b00, + a11 * b07 - a10 * b09 - a12 * b06, + a00 * b09 - a01 * b07 + a02 * b06, + a31 * b01 - a30 * b03 - a32 * b00, + a20 * b03 - a21 * b01 + a22 * b00) / det; + + return mat4(mi[0][0], mi[1][0], mi[2][0], mi[3][0], + mi[0][1], mi[1][1], mi[2][1], mi[3][1], + mi[0][2], mi[1][2], mi[2][2], mi[3][2], + mi[0][3], mi[1][3], mi[2][3], mi[3][3]); + } + #endif + #endif + + vec3 perturbNormalBase(mat3 cotangentFrame, vec3 normal, float scale) + { + #ifdef NORMALXYSCALE + normal = normalize(normal * vec3(scale, scale, 1.0)); + #endif + + return normalize(cotangentFrame * normal); + } + + vec3 perturbNormal(mat3 cotangentFrame, vec3 textureSample, float scale) + { + return perturbNormalBase(cotangentFrame, textureSample * 2.0 - 1.0, scale); + } + + // Thanks to http://www.thetenthplanet.de/archives/1180 + mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv, vec2 tangentSpaceParams) + { + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + + // solve the linear system + vec3 dp2perp = cross(dp2, normal); + vec3 dp1perp = cross(normal, dp1); + vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 bitangent = dp2perp * duv1.y + dp1perp * duv2.y; + + // invert the tangent/bitangent if requested + tangent *= tangentSpaceParams.x; + bitangent *= tangentSpaceParams.y; + + // construct a scale-invariant frame + float det = max(dot(tangent, tangent), dot(bitangent, bitangent)); + float invmax = det == 0.0 ? 0.0 : inversesqrt(det); + return mat3(tangent * invmax, bitangent * invmax, normal); + } +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js new file mode 100644 index 00000000000..918a4e2554e --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js @@ -0,0 +1,72 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapFragmentMainFunctions"; +const shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) +#if defined(TANGENT) && defined(NORMAL) +varying mat3 vTBN; +#endif +#ifdef OBJECTSPACE_NORMALMAP +uniform mat4 normalMatrix; +#if defined(WEBGL2) || defined(WEBGPU) +mat4 toNormalMatrix(mat4 wMatrix) +{mat4 ret=inverse(wMatrix);ret=transpose(ret);ret[0][3]=0.;ret[1][3]=0.;ret[2][3]=0.;ret[3]=vec4(0.,0.,0.,1.);return ret;} +#else +mat4 toNormalMatrix(mat4 m) +{float +a00=m[0][0],a01=m[0][1],a02=m[0][2],a03=m[0][3], +a10=m[1][0],a11=m[1][1],a12=m[1][2],a13=m[1][3], +a20=m[2][0],a21=m[2][1],a22=m[2][2],a23=m[2][3], +a30=m[3][0],a31=m[3][1],a32=m[3][2],a33=m[3][3], +b00=a00*a11-a01*a10, +b01=a00*a12-a02*a10, +b02=a00*a13-a03*a10, +b03=a01*a12-a02*a11, +b04=a01*a13-a03*a11, +b05=a02*a13-a03*a12, +b06=a20*a31-a21*a30, +b07=a20*a32-a22*a30, +b08=a20*a33-a23*a30, +b09=a21*a32-a22*a31, +b10=a21*a33-a23*a31, +b11=a22*a33-a23*a32, +det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;mat4 mi=mat4( +a11*b11-a12*b10+a13*b09, +a02*b10-a01*b11-a03*b09, +a31*b05-a32*b04+a33*b03, +a22*b04-a21*b05-a23*b03, +a12*b08-a10*b11-a13*b07, +a00*b11-a02*b08+a03*b07, +a32*b02-a30*b05-a33*b01, +a20*b05-a22*b02+a23*b01, +a10*b10-a11*b08+a13*b06, +a01*b08-a00*b10-a03*b06, +a30*b04-a31*b02+a33*b00, +a21*b02-a20*b04-a23*b00, +a11*b07-a10*b09-a12*b06, +a00*b09-a01*b07+a02*b06, +a31*b01-a30*b03-a32*b00, +a20*b03-a21*b01+a22*b00)/det;return mat4(mi[0][0],mi[1][0],mi[2][0],mi[3][0], +mi[0][1],mi[1][1],mi[2][1],mi[3][1], +mi[0][2],mi[1][2],mi[2][2],mi[3][2], +mi[0][3],mi[1][3],mi[2][3],mi[3][3]);} +#endif +#endif +vec3 perturbNormalBase(mat3 cotangentFrame,vec3 normal,float scale) +{ +#ifdef NORMALXYSCALE +normal=normalize(normal*vec3(scale,scale,1.0)); +#endif +return normalize(cotangentFrame*normal);} +vec3 perturbNormal(mat3 cotangentFrame,vec3 textureSample,float scale) +{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);} +mat3 cotangent_frame(vec3 normal,vec3 p,vec2 uv,vec2 tangentSpaceParams) +{vec3 dp1=dFdx(p);vec3 dp2=dFdy(p);vec2 duv1=dFdx(uv);vec2 duv2=dFdy(uv);vec3 dp2perp=cross(dp2,normal);vec3 dp1perp=cross(normal,dp1);vec3 tangent=dp2perp*duv1.x+dp1perp*duv2.x;vec3 bitangent=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;float det=max(dot(tangent,tangent),dot(bitangent,bitangent));float invmax=det==0.0 ? 0.0 : inversesqrt(det);return mat3(tangent*invmax,bitangent*invmax,normal);} +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStore[name]) { + ShaderStore.IncludesShadersStore[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragmentMainFunctions = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragmentMainFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map new file mode 100644 index 00000000000..3d2d817225e --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragmentMainFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentMainFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,uCAAuC,CAAC;AACrD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6Dd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragmentMainFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL)\n#if defined(TANGENT) && defined(NORMAL) \nvarying mat3 vTBN;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\nuniform mat4 normalMatrix;\n#if defined(WEBGL2) || defined(WEBGPU)\nmat4 toNormalMatrix(mat4 wMatrix)\n{mat4 ret=inverse(wMatrix);ret=transpose(ret);ret[0][3]=0.;ret[1][3]=0.;ret[2][3]=0.;ret[3]=vec4(0.,0.,0.,1.);return ret;}\n#else\nmat4 toNormalMatrix(mat4 m)\n{float\na00=m[0][0],a01=m[0][1],a02=m[0][2],a03=m[0][3],\na10=m[1][0],a11=m[1][1],a12=m[1][2],a13=m[1][3],\na20=m[2][0],a21=m[2][1],a22=m[2][2],a23=m[2][3],\na30=m[3][0],a31=m[3][1],a32=m[3][2],a33=m[3][3],\nb00=a00*a11-a01*a10,\nb01=a00*a12-a02*a10,\nb02=a00*a13-a03*a10,\nb03=a01*a12-a02*a11,\nb04=a01*a13-a03*a11,\nb05=a02*a13-a03*a12,\nb06=a20*a31-a21*a30,\nb07=a20*a32-a22*a30,\nb08=a20*a33-a23*a30,\nb09=a21*a32-a22*a31,\nb10=a21*a33-a23*a31,\nb11=a22*a33-a23*a32,\ndet=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;mat4 mi=mat4(\na11*b11-a12*b10+a13*b09,\na02*b10-a01*b11-a03*b09,\na31*b05-a32*b04+a33*b03,\na22*b04-a21*b05-a23*b03,\na12*b08-a10*b11-a13*b07,\na00*b11-a02*b08+a03*b07,\na32*b02-a30*b05-a33*b01,\na20*b05-a22*b02+a23*b01,\na10*b10-a11*b08+a13*b06,\na01*b08-a00*b10-a03*b06,\na30*b04-a31*b02+a33*b00,\na21*b02-a20*b04-a23*b00,\na11*b07-a10*b09-a12*b06,\na00*b09-a01*b07+a02*b06,\na31*b01-a30*b03-a32*b00,\na20*b03-a21*b01+a22*b00)/det;return mat4(mi[0][0],mi[1][0],mi[2][0],mi[3][0],\nmi[0][1],mi[1][1],mi[2][1],mi[3][1],\nmi[0][2],mi[1][2],mi[2][2],mi[3][2],\nmi[0][3],mi[1][3],mi[2][3],mi[3][3]);}\n#endif\n#endif\nvec3 perturbNormalBase(mat3 cotangentFrame,vec3 normal,float scale)\n{\n#ifdef NORMALXYSCALE\nnormal=normalize(normal*vec3(scale,scale,1.0));\n#endif\nreturn normalize(cotangentFrame*normal);}\nvec3 perturbNormal(mat3 cotangentFrame,vec3 textureSample,float scale)\n{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);}\nmat3 cotangent_frame(vec3 normal,vec3 p,vec2 uv,vec2 tangentSpaceParams)\n{vec3 dp1=dFdx(p);vec3 dp2=dFdy(p);vec2 duv1=dFdx(uv);vec2 duv2=dFdy(uv);vec3 dp2perp=cross(dp2,normal);vec3 dp1perp=cross(normal,dp1);vec3 tangent=dp2perp*duv1.x+dp1perp*duv2.x;vec3 bitangent=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;float det=max(dot(tangent,tangent),dot(bitangent,bitangent));float invmax=det==0.0 ? 0.0 : inversesqrt(det);return mat3(tangent*invmax,bitangent*invmax,normal);}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentMainFunctions = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx new file mode 100644 index 00000000000..fe467dd1c3a --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx @@ -0,0 +1,8 @@ +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + vec3 tbnNormal = normalize(normalUpdated); + vec3 tbnTangent = normalize(tangentUpdated.xyz); + vec3 tbnBitangent = cross(tbnNormal, tbnTangent) * tangentUpdated.w; + vTBN = mat3(finalWorld) * mat3(tbnTangent, tbnBitangent, tbnNormal); + #endif +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js new file mode 100644 index 00000000000..fc749f98a86 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js @@ -0,0 +1,16 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapVertex"; +const shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#if defined(TANGENT) && defined(NORMAL) +vec3 tbnNormal=normalize(normalUpdated);vec3 tbnTangent=normalize(tangentUpdated.xyz);vec3 tbnBitangent=cross(tbnNormal,tbnTangent)*tangentUpdated.w;vTBN=mat3(finalWorld)*mat3(tbnTangent,tbnBitangent,tbnNormal); +#endif +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStore[name]) { + ShaderStore.IncludesShadersStore[name] = shader; +} +/** @internal */ +export const openpbrNormalMapVertex = { name, shader }; +//# sourceMappingURL=openpbrNormalMapVertex.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map new file mode 100644 index 00000000000..b3b110c800a --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapVertex.js","sourceRoot":"","sources":["openpbrNormalMapVertex.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,wBAAwB,CAAC;AACtC,MAAM,MAAM,GAAG;;;;;CAKd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapVertex\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nvec3 tbnNormal=normalize(normalUpdated);vec3 tbnTangent=normalize(tangentUpdated.xyz);vec3 tbnBitangent=cross(tbnNormal,tbnTangent)*tangentUpdated.w;vTBN=mat3(finalWorld)*mat3(tbnTangent,tbnBitangent,tbnNormal);\n#endif\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapVertex = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx new file mode 100644 index 00000000000..12b795200ee --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx @@ -0,0 +1,5 @@ +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + varying mat3 vTBN; + #endif +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js new file mode 100644 index 00000000000..9d691d6b7e3 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js @@ -0,0 +1,16 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapVertexDeclaration"; +const shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#if defined(TANGENT) && defined(NORMAL) +varying mat3 vTBN; +#endif +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStore[name]) { + ShaderStore.IncludesShadersStore[name] = shader; +} +/** @internal */ +export const openpbrNormalMapVertexDeclaration = { name, shader }; +//# sourceMappingURL=openpbrNormalMapVertexDeclaration.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map new file mode 100644 index 00000000000..d48345c1b0f --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapVertexDeclaration.js","sourceRoot":"","sources":["openpbrNormalMapVertexDeclaration.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;CAKd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapVertexDeclaration\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL) \nvarying mat3 vTBN;\n#endif\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapVertexDeclaration = { name, shader };\n"]} \ 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 index 4997164b647..3dfa76671f8 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -56,9 +56,9 @@ uniform vec2 vSpecularColorInfos; uniform mat4 specularColorMatrix; #endif -#ifdef BUMP -uniform vec3 vBumpInfos; -uniform mat4 bumpMatrix; +#ifdef GEOMETRY_NORMAL +uniform vec2 vGeometryNormalInfos; +uniform mat4 geometryNormalMatrix; #endif #ifdef POINTSIZE diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 32da1a6614d..9ff73273a6d 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -2,7 +2,7 @@ #define CUSTOM_FRAGMENT_EXTENSION -#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) +#if defined(GEOMETRY_NORMAL) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) #extension GL_OES_standard_derivatives : enable #endif @@ -51,8 +51,8 @@ precision highp float; #include #include #include -#include -#include +#include +#include #ifdef REFLECTION #include @@ -76,7 +76,7 @@ void main(void) { // _____________________________ Geometry Information ____________________________ #include - #include + #include #include @@ -231,7 +231,7 @@ vec4 specularColor = vSpecularColor; #endif // _____________________________ Compute Geometry info _________________________________ - #include + #include // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 1f3ffdf2f8c..8961ec24981 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -39,11 +39,11 @@ attribute vec4 color; #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #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) @@ -67,8 +67,7 @@ varying vec3 vPositionW; varying vec4 vColor; #endif -// This is just including TBN, if needed. "Bump" isn't really a great name. -#include +#include #include #include #include<__decl__lightVxFragment>[0..maxSimultaneousLights] @@ -219,17 +218,17 @@ void main(void) { #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_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.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 +#include // Clip plane #include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index a401a7e0a8d..65f1c6af73f 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -1,9 +1,6 @@ uniform vLightmapInfos: vec2f; -uniform vBumpInfos: vec3f; - uniform lightmapMatrix: mat4x4f; -uniform bumpMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; uniform vLightingIntensity: vec4f; uniform pointSize: f32; @@ -60,6 +57,8 @@ uniform vSpecularColorInfos: vec2f; uniform specularColorMatrix: mat4x4f; uniform vBaseMetalRoughInfos: vec2f; uniform baseMetalRoughMatrix: mat4x4f; +uniform vGeometryNormalInfos: vec2f; +uniform geometryNormalMatrix: mat4x4f; uniform vGeometryOpacityInfos: vec2f; uniform geometryOpacityMatrix: mat4x4f; uniform vEmissionInfos: vec2f; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx new file mode 100644 index 00000000000..4e3cb25c47f --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx @@ -0,0 +1,31 @@ +struct ambientOcclusionOutParams +{ + ambientOcclusionColor: vec3f, +#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) + ambientOcclusionColorMap: vec3f +#endif +}; + +#define pbr_inline +fn ambientOcclusionBlock( +#ifdef AMBIENT_OCCLUSION + ambientOcclusionFromTexture: vec3f, + ambientOcclusionInfos: vec2f +#endif +) -> ambientOcclusionOutParams +{ + var outParams: ambientOcclusionOutParams; + var ambientOcclusionColor: vec3f = vec3f(1., 1., 1.); + + #ifdef AMBIENT_OCCLUSION + ambientOcclusionColor = vec3f(ambientOcclusionFromTexture.r * ambientOcclusionInfos.y); + + #if DEBUGMODE > 0 + outParams.ambientOcclusionColorMap = ambientOcclusionFromTexture; + #endif + #endif + + outParams.ambientOcclusionColor = ambientOcclusionColor; + + return outParams; +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx new file mode 100644 index 00000000000..dd0564f851e --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx @@ -0,0 +1,35 @@ +var NdotVUnclamped: f32 = dot(normalW, viewDirectionW); +// The order 1886 page 3. +var NdotV: f32 = absEps(NdotVUnclamped); +var alphaG: f32 = convertRoughnessToAverageSlope(roughness); +var AARoughnessFactors: vec2f = getAARoughnessFactors(normalW.xyz); + +#ifdef SPECULARAA + // Adapt linear roughness (alphaG) to geometric curvature of the current pixel. + alphaG += AARoughnessFactors.y; +#endif + +#if defined(ENVIRONMENTBRDF) + // BRDF Lookup + var environmentBrdf: vec3f = getBRDFLookup(NdotV, roughness); +#endif + +#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + #ifdef RADIANCEOCCLUSION + #ifdef AMBIENTINGRAYSCALE + var ambientMonochrome: f32 = aoOut.ambientOcclusionColor.r; + #else + var ambientMonochrome: f32 = getLuminance(aoOut.ambientOcclusionColor); + #endif + + var seo: f32 = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped); + #endif + + #ifdef HORIZONOCCLUSION + #ifdef GEOMETRY_NORMAL + #ifdef REFLECTIONMAP_3D + var eho: f32 = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); + #endif + #endif + #endif +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx index e1463573150..44d5e5c6e63 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx @@ -23,7 +23,7 @@ #endif #ifdef HORIZONOCCLUSION - #ifdef BUMP + #ifdef GEOMETRY_NORMAL #ifdef REFLECTIONMAP_3D colorSpecularEnvironmentReflectance *= eho; #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.fx new file mode 100644 index 00000000000..df58b0dcbc6 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.fx @@ -0,0 +1,77 @@ +var uvOffset: vec2f = vec2f(0.0, 0.0); + +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) + #ifdef NORMALXYSCALE + var normalScale: f32 = 1.0; + #elif defined(GEOMETRY_NORMAL) + var normalScale: f32 = uniforms.vGeometryNormalInfos.y; + #else + var normalScale: f32 = 1.0; + #endif + + #if defined(TANGENT) && defined(NORMAL) + var TBN: mat3x3f = mat3x3(input.vTBN0, input.vTBN1, input.vTBN2); + #elif defined(GEOMETRY_NORMAL) + // flip the uv for the backface + var TBNUV: vec2f = select(-fragmentInputs.vGeometryNormalUV, fragmentInputs.vGeometryNormalUV, fragmentInputs.frontFacing); + var TBN: mat3x3f = cotangent_frame(normalW * normalScale, input.vPositionW, TBNUV, uniforms.vTangentSpaceParams); + #else + // flip the uv for the backface + var TBNUV: vec2f = select(-fragmentInputs.vDetailUV, fragmentInputs.vDetailUV, fragmentInputs.frontFacing); + var TBN: mat3x3f = cotangent_frame(normalW * normalScale, input.vPositionW, TBNUV, vec2f(1., 1.)); + #endif +#elif defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + var TBN: mat3x3f = mat3x3(input.vTBN0, input.vTBN1, input.vTBN2); + #else + // flip the uv for the backface + var TBNUV: vec2f = select( -fragmentInputs.vMainUV1, fragmentInputs.vMainUV1, fragmentInputs.frontFacing); + var TBN: mat3x3f = cotangent_frame(normalW, input.vPositionW, TBNUV, vec2f(1., 1.)); + #endif +#endif + +#ifdef PARALLAX + var invTBN: mat3x3f = transposeMat3(TBN); + + #ifdef PARALLAXOCCLUSION + // TODO: Implement parallax occlusion scale + // uvOffset = parallaxOcclusion(invTBN * -viewDirectionW, invTBN * normalW, fragmentInputs.vGeometryNormalUV, uniforms.vGeometryNormalInfos.z); + #else + // uvOffset = parallaxOffset(invTBN * viewDirectionW, uniforms.vGeometryNormalInfos.z); + #endif +#endif + +#ifdef DETAIL + var detailColor: vec4f = textureSample(detailSampler, detailSamplerSampler, fragmentInputs.vDetailUV + uvOffset); + var detailNormalRG: vec2f = detailColor.wy * 2.0 - 1.0; + var detailNormalB: f32 = sqrt(1. - saturate(dot(detailNormalRG, detailNormalRG))); + var detailNormal: vec3f = vec3f(detailNormalRG, detailNormalB); +#endif + +#ifdef GEOMETRY_NORMAL + #ifdef OBJECTSPACE_NORMALMAP + + #define CUSTOM_FRAGMENT_BUMP_FRAGMENT + + normalW = normalize(textureSample(geometryNormalSampler, geometryNormalSamplerSampler, fragmentInputs.vGeometryNormalUV).xyz * 2.0 - 1.0); + normalW = normalize(mat3x3f(uniforms.normalMatrix[0].xyz, uniforms.normalMatrix[1].xyz, uniforms.normalMatrix[2].xyz) * normalW); + #elif !defined(DETAIL) + normalW = perturbNormal(TBN, textureSample(geometryNormalSampler, geometryNormalSamplerSampler, fragmentInputs.vGeometryNormalUV + uvOffset).xyz, uniforms.vGeometryNormalInfos.y); + #else + var sampledNormal: vec3f = textureSample(geometryNormalSampler, geometryNormalSamplerSampler, fragmentInputs.vGeometryNormalUV + uvOffset).xyz * 2.0 - 1.0; + // Reference for normal blending: https://blog.selfshadow.com/publications/blending-in-detail/ + #if DETAIL_NORMALBLENDMETHOD == 0 // whiteout + detailNormal = vec3f(detailNormal.xy * uniforms.vDetailInfos.z, detailNormal.z); + var blendedNormal: vec3f = normalize( vec3f(sampledNormal.xy + detailNormal.xy, sampledNormal.z * detailNormal.z)); + #elif DETAIL_NORMALBLENDMETHOD == 1 // RNM + detailNormal = vec3f(detailNormal.xy * uniforms.vDetailInfos.z, detailNormal.z); + sampledNormal += vec3f(0.0, 0.0, 1.0); + detailNormal *= vec3f(-1.0, -1.0, 1.0); + var blendedNormal: vec3f = sampledNormal * dot(sampledNormal, detailNormal) / sampledNormal.z - detailNormal; + #endif + normalW = perturbNormalBase(TBN, blendedNormal, uniforms.vGeometryNormalInfos.y); + #endif +#elif defined(DETAIL) + detailNormal = vec3f(detailNormal.xy * uniforms.vDetailInfos.z, detailNormal.z); + normalW = perturbNormalBase(TBN, detailNormal, uniforms.vDetailInfos.z); +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js new file mode 100644 index 00000000000..8963b3b5be0 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js @@ -0,0 +1,63 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapFragment"; +const shader = `var uvOffset: vec2f= vec2f(0.0,0.0); +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) +#ifdef NORMALXYSCALE +var normalScale: f32=1.0; +#elif defined(GEOMETRY_NORMAL) +var normalScale: f32=uniforms.vGeometryNormalInfos.y; +#else +var normalScale: f32=1.0; +#endif +#if defined(TANGENT) && defined(NORMAL) +var TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); +#elif defined(GEOMETRY_NORMAL) +var TBNUV: vec2f=select(-fragmentInputs.vGeometryNormalUV,fragmentInputs.vGeometryNormalUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV,uniforms.vTangentSpaceParams); +#else +var TBNUV: vec2f=select(-fragmentInputs.vDetailUV,fragmentInputs.vDetailUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV, vec2f(1.,1.)); +#endif +#elif defined(ANISOTROPIC) +#if defined(TANGENT) && defined(NORMAL) +var TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); +#else +var TBNUV: vec2f=select( -fragmentInputs.vMainUV1,fragmentInputs.vMainUV1,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW,input.vPositionW,TBNUV, vec2f(1.,1.)); +#endif +#endif +#ifdef PARALLAX +var invTBN: mat3x3f=transposeMat3(TBN); +#ifdef PARALLAXOCCLUSION +uvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,fragmentInputs.vGeometryNormalUV,uniforms.vGeometryNormalInfos.z); +#else +uvOffset=parallaxOffset(invTBN*viewDirectionW,uniforms.vGeometryNormalInfos.z); +#endif +#endif +#ifdef DETAIL +var detailColor: vec4f=textureSample(detailSampler,detailSamplerSampler,fragmentInputs.vDetailUV+uvOffset);var detailNormalRG: vec2f=detailColor.wy*2.0-1.0;var detailNormalB: f32=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));var detailNormal: vec3f= vec3f(detailNormalRG,detailNormalB); +#endif +#ifdef GEOMETRY_NORMAL +#ifdef OBJECTSPACE_NORMALMAP +#define CUSTOM_FRAGMENT_BUMP_FRAGMENT +normalW=normalize(textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3x3f(uniforms.normalMatrix[0].xyz,uniforms.normalMatrix[1].xyz,uniforms.normalMatrix[2].xyz)*normalW); +#elif !defined(DETAIL) +normalW=perturbNormal(TBN,textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz,uniforms.vGeometryNormalInfos.y); +#else +var bumpNormal: vec3f=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz*2.0-1.0; +#if DETAIL_NORMALBLENDMETHOD==0 +detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);var blendedNormal: vec3f=normalize( vec3f(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z)); +#elif DETAIL_NORMALBLENDMETHOD==1 +detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);bumpNormal+= vec3f(0.0,0.0,1.0);detailNormal*= vec3f(-1.0,-1.0,1.0);var blendedNormal: vec3f=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal; +#endif +normalW=perturbNormalBase(TBN,blendedNormal,uniforms.vGeometryNormalInfos.y); +#endif +#elif defined(DETAIL) +detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);normalW=perturbNormalBase(TBN,detailNormal,uniforms.vDetailInfos.z); +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStoreWGSL[name]) { + ShaderStore.IncludesShadersStoreWGSL[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragmentWGSL = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragment.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map new file mode 100644 index 00000000000..5ec48fd9e3d --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragment.js","sourceRoot":"","sources":["openpbrNormalMapFragment.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,0BAA0B,CAAC;AACxC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragment\";\nconst shader = `var uvOffset: vec2f= vec2f(0.0,0.0);\n#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL)\n#ifdef NORMALXYSCALE\nvar normalScale: f32=1.0;\n#elif defined(GEOMETRY_NORMAL)\nvar normalScale: f32=uniforms.vGeometryNormalInfos.y;\n#else\nvar normalScale: f32=1.0;\n#endif\n#if defined(TANGENT) && defined(NORMAL)\nvar TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); \n#elif defined(GEOMETRY_NORMAL)\nvar TBNUV: vec2f=select(-fragmentInputs.vGeometryNormalUV,fragmentInputs.vGeometryNormalUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV,uniforms.vTangentSpaceParams);\n#else\nvar TBNUV: vec2f=select(-fragmentInputs.vDetailUV,fragmentInputs.vDetailUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV, vec2f(1.,1.));\n#endif\n#elif defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nvar TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); \n#else\nvar TBNUV: vec2f=select( -fragmentInputs.vMainUV1,fragmentInputs.vMainUV1,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW,input.vPositionW,TBNUV, vec2f(1.,1.));\n#endif\n#endif\n#ifdef PARALLAX\nvar invTBN: mat3x3f=transposeMat3(TBN);\n#ifdef PARALLAXOCCLUSION\nuvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,fragmentInputs.vGeometryNormalUV,uniforms.vGeometryNormalInfos.z);\n#else\nuvOffset=parallaxOffset(invTBN*viewDirectionW,uniforms.vGeometryNormalInfos.z);\n#endif\n#endif\n#ifdef DETAIL\nvar detailColor: vec4f=textureSample(detailSampler,detailSamplerSampler,fragmentInputs.vDetailUV+uvOffset);var detailNormalRG: vec2f=detailColor.wy*2.0-1.0;var detailNormalB: f32=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));var detailNormal: vec3f= vec3f(detailNormalRG,detailNormalB);\n#endif\n#ifdef GEOMETRY_NORMAL\n#ifdef OBJECTSPACE_NORMALMAP\n#define CUSTOM_FRAGMENT_BUMP_FRAGMENT\nnormalW=normalize(textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3x3f(uniforms.normalMatrix[0].xyz,uniforms.normalMatrix[1].xyz,uniforms.normalMatrix[2].xyz)*normalW);\n#elif !defined(DETAIL)\nnormalW=perturbNormal(TBN,textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz,uniforms.vGeometryNormalInfos.y);\n#else\nvar bumpNormal: vec3f=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz*2.0-1.0;\n#if DETAIL_NORMALBLENDMETHOD==0 \ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);var blendedNormal: vec3f=normalize( vec3f(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z));\n#elif DETAIL_NORMALBLENDMETHOD==1 \ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);bumpNormal+= vec3f(0.0,0.0,1.0);detailNormal*= vec3f(-1.0,-1.0,1.0);var blendedNormal: vec3f=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal;\n#endif\nnormalW=perturbNormalBase(TBN,blendedNormal,uniforms.vGeometryNormalInfos.y);\n#endif\n#elif defined(DETAIL)\ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);normalW=perturbNormalBase(TBN,detailNormal,uniforms.vDetailInfos.z);\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx new file mode 100644 index 00000000000..36476080e53 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx @@ -0,0 +1,79 @@ +#if defined(GEOMETRY_NORMAL) + #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) +#endif + +#if defined(DETAIL) + #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) +#endif + +#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) + const minSamples: f32 = 4.; + const maxSamples: f32 = 15.; + const iMaxSamples: i32 = 15; + + // http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262 + fn parallaxOcclusion(vViewDirCoT: vec3f, vNormalCoT: vec3f, texCoord: vec2f, parallaxScale: f32) -> vec2f { + + var parallaxLimit: f32 = length(vViewDirCoT.xy) / vViewDirCoT.z; + parallaxLimit *= parallaxScale; + var vOffsetDir: vec2f = normalize(vViewDirCoT.xy); + var vMaxOffset: vec2f = vOffsetDir * parallaxLimit; + var numSamples: f32 = maxSamples + (dot(vViewDirCoT, vNormalCoT) * (minSamples - maxSamples)); + var stepSize: f32 = 1.0 / numSamples; + + // Initialize the starting view ray height and the texture offsets. + var currRayHeight: f32 = 1.0; + var vCurrOffset: vec2f = vec2f(0, 0); + var vLastOffset: vec2f = vec2f(0, 0); + + var lastSampledHeight: f32 = 1.0; + var currSampledHeight: f32 = 1.0; + + var keepWorking: bool = true; + for (var i: i32 = 0; i < iMaxSamples; i++) + { + currSampledHeight = textureSample(geometryNormalSampler, geometryNormalSamplerSampler, texCoord + vCurrOffset).w; + + // Test if the view ray has intersected the surface. + if (!keepWorking) + { + // do nothing + } + else if (currSampledHeight > currRayHeight) + { + var delta1: f32 = currSampledHeight - currRayHeight; + var delta2: f32 = (currRayHeight + stepSize) - lastSampledHeight; + var ratio: f32 = delta1 / (delta1 + delta2); + vCurrOffset = (ratio)* vLastOffset + (1.0 - ratio) * vCurrOffset; + + keepWorking = false; + } + else + { + currRayHeight -= stepSize; + vLastOffset = vCurrOffset; + #ifdef PARALLAX_RHS + vCurrOffset -= stepSize * vMaxOffset; + #else + vCurrOffset += stepSize * vMaxOffset; + #endif + + lastSampledHeight = currSampledHeight; + } + } + + return vCurrOffset; + } + + fn parallaxOffset(viewDir: vec3f, heightScale: f32) -> vec2f + { + // calculate amount of offset for Parallax Mapping With Offset Limiting + var height: f32 = textureSample(geometryNormalSampler, geometryNormalSamplerSampler, fragmentInputs.vGeometryNormalUV).w; + var texCoordOffset: vec2f = heightScale * viewDir.xy * height; + #ifdef PARALLAX_RHS + return texCoordOffset; + #else + return -texCoordOffset; + #endif + } +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js new file mode 100644 index 00000000000..4c7afb24c09 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js @@ -0,0 +1,42 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +import "./samplerFragmentDeclaration"; +const name = "openpbrNormalMapFragmentFunctions"; +const shader = `#if defined(GEOMETRY_NORMAL) +#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) +#endif +#if defined(DETAIL) +#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) +#endif +#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) +const minSamples: f32=4.;const maxSamples: f32=15.;const iMaxSamples: i32=15;fn parallaxOcclusion(vViewDirCoT: vec3f,vNormalCoT: vec3f,texCoord: vec2f,parallaxScale: f32)->vec2f {var parallaxLimit: f32=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;var vOffsetDir: vec2f=normalize(vViewDirCoT.xy);var vMaxOffset: vec2f=vOffsetDir*parallaxLimit;var numSamples: f32=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));var stepSize: f32=1.0/numSamples;var currRayHeight: f32=1.0;var vCurrOffset: vec2f= vec2f(0,0);var vLastOffset: vec2f= vec2f(0,0);var lastSampledHeight: f32=1.0;var currSampledHeight: f32=1.0;var keepWorking: bool=true;for (var i: i32=0; icurrRayHeight) +{var delta1: f32=currSampledHeight-currRayHeight;var delta2: f32=(currRayHeight+stepSize)-lastSampledHeight;var ratio: f32=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;} +else +{currRayHeight-=stepSize;vLastOffset=vCurrOffset; +#ifdef PARALLAX_RHS +vCurrOffset-=stepSize*vMaxOffset; +#else +vCurrOffset+=stepSize*vMaxOffset; +#endif +lastSampledHeight=currSampledHeight;}} +return vCurrOffset;} +fn parallaxOffset(viewDir: vec3f,heightScale: f32)->vec2f +{var height: f32=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).w;var texCoordOffset: vec2f=heightScale*viewDir.xy*height; +#ifdef PARALLAX_RHS +return texCoordOffset; +#else +return -texCoordOffset; +#endif +} +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStoreWGSL[name]) { + ShaderStore.IncludesShadersStoreWGSL[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragmentFunctionsWGSL = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragmentFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map new file mode 100644 index 00000000000..9152b6cb7f5 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragmentFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,8BAA8B,CAAC;AAEtC,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\nimport \"./samplerFragmentDeclaration\";\n\nconst name = \"openpbrNormalMapFragmentFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL)\n#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal)\n#endif\n#if defined(DETAIL)\n#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail)\n#endif\n#if defined(GEOMETRY_NORMAL) && defined(PARALLAX)\nconst minSamples: f32=4.;const maxSamples: f32=15.;const iMaxSamples: i32=15;fn parallaxOcclusion(vViewDirCoT: vec3f,vNormalCoT: vec3f,texCoord: vec2f,parallaxScale: f32)->vec2f {var parallaxLimit: f32=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;var vOffsetDir: vec2f=normalize(vViewDirCoT.xy);var vMaxOffset: vec2f=vOffsetDir*parallaxLimit;var numSamples: f32=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));var stepSize: f32=1.0/numSamples;var currRayHeight: f32=1.0;var vCurrOffset: vec2f= vec2f(0,0);var vLastOffset: vec2f= vec2f(0,0);var lastSampledHeight: f32=1.0;var currSampledHeight: f32=1.0;var keepWorking: bool=true;for (var i: i32=0; icurrRayHeight)\n{var delta1: f32=currSampledHeight-currRayHeight;var delta2: f32=(currRayHeight+stepSize)-lastSampledHeight;var ratio: f32=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;}\nelse\n{currRayHeight-=stepSize;vLastOffset=vCurrOffset;\n#ifdef PARALLAX_RHS\nvCurrOffset-=stepSize*vMaxOffset;\n#else\nvCurrOffset+=stepSize*vMaxOffset;\n#endif\nlastSampledHeight=currSampledHeight;}}\nreturn vCurrOffset;}\nfn parallaxOffset(viewDir: vec3f,heightScale: f32)->vec2f\n{var height: f32=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).w;var texCoordOffset: vec2f=heightScale*viewDir.xy*height;\n#ifdef PARALLAX_RHS\nreturn texCoordOffset;\n#else\nreturn -texCoordOffset;\n#endif\n}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentFunctionsWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx new file mode 100644 index 00000000000..6036dc2be86 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx @@ -0,0 +1,109 @@ +#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) + #if defined(TANGENT) && defined(NORMAL) + varying vTBN0: vec3f; + varying vTBN1: vec3f; + varying vTBN2: vec3f; + #endif + + #ifdef OBJECTSPACE_NORMALMAP + uniform normalMatrix: mat4x4f; + + fn toNormalMatrix(m: mat4x4f) -> mat4x4f + { + var a00 = m[0][0]; + var a01 = m[0][1]; + var a02 = m[0][2]; + var a03 = m[0][3]; + var a10 = m[1][0]; + var a11 = m[1][1]; + var a12 = m[1][2]; + var a13 = m[1][3]; + var a20 = m[2][0]; + var a21 = m[2][1]; + var a22 = m[2][2]; + var a23 = m[2][3]; + var a30 = m[3][0]; + var a31 = m[3][1]; + var a32 = m[3][2]; + var a33 = m[3][3]; + + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; + + var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + var mi = mat4x4( + (a11 * b11 - a12 * b10 + a13 * b09) / det, + (a02 * b10 - a01 * b11 - a03 * b09) / det, + (a31 * b05 - a32 * b04 + a33 * b03) / det, + (a22 * b04 - a21 * b05 - a23 * b03) / det, + (a12 * b08 - a10 * b11 - a13 * b07) / det, + (a00 * b11 - a02 * b08 + a03 * b07) / det, + (a32 * b02 - a30 * b05 - a33 * b01) / det, + (a20 * b05 - a22 * b02 + a23 * b01) / det, + (a10 * b10 - a11 * b08 + a13 * b06) / det, + (a01 * b08 - a00 * b10 - a03 * b06) / det, + (a30 * b04 - a31 * b02 + a33 * b00) / det, + (a21 * b02 - a20 * b04 - a23 * b00) / det, + (a11 * b07 - a10 * b09 - a12 * b06) / det, + (a00 * b09 - a01 * b07 + a02 * b06) / det, + (a31 * b01 - a30 * b03 - a32 * b00) / det, + (a20 * b03 - a21 * b01 + a22 * b00) / det); + + return mat4x4(mi[0][0], mi[1][0], mi[2][0], mi[3][0], + mi[0][1], mi[1][1], mi[2][1], mi[3][1], + mi[0][2], mi[1][2], mi[2][2], mi[3][2], + mi[0][3], mi[1][3], mi[2][3], mi[3][3]); + } + #endif + + fn perturbNormalBase(cotangentFrame: mat3x3f, normal: vec3f, scale: f32) -> vec3f + { + var output = normal; + #ifdef NORMALXYSCALE + output = normalize(output * vec3f(scale, scale, 1.0)); + #endif + + return normalize(cotangentFrame * output); + } + + fn perturbNormal(cotangentFrame: mat3x3f, textureSample: vec3f, scale: f32) -> vec3f + { + return perturbNormalBase(cotangentFrame, textureSample * 2.0 - 1.0, scale); + } + + // Thanks to http://www.thetenthplanet.de/archives/1180 + fn cotangent_frame(normal: vec3f, p: vec3f, uv: vec2f, tangentSpaceParams: vec2f) -> mat3x3f + { + // get edge vectors of the pixel triangle + var dp1: vec3f = dpdx(p); + var dp2: vec3f = dpdy(p); + var duv1: vec2f = dpdx(uv); + var duv2: vec2f = dpdy(uv); + + // solve the linear system + var dp2perp: vec3f = cross(dp2, normal); + var dp1perp: vec3f = cross(normal, dp1); + var tangent: vec3f = dp2perp * duv1.x + dp1perp * duv2.x; + var bitangent: vec3f = dp2perp * duv1.y + dp1perp * duv2.y; + + // invert the tangent/bitangent if requested + tangent *= tangentSpaceParams.x; + bitangent *= tangentSpaceParams.y; + + // construct a scale-invariant frame + var det: f32 = max(dot(tangent, tangent), dot(bitangent, bitangent)); + var invmax: f32 = select(inverseSqrt(det), 0.0, det == 0.0); + return mat3x3f(tangent * invmax, bitangent * invmax, normal); + } +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js new file mode 100644 index 00000000000..39b39ef3f1a --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js @@ -0,0 +1,51 @@ +// Do not edit. +import { ShaderStore } from "../../Engines/shaderStore"; +const name = "openpbrNormalMapFragmentMainFunctions"; +const shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) +#if defined(TANGENT) && defined(NORMAL) +varying vTBN0: vec3f;varying vTBN1: vec3f;varying vTBN2: vec3f; +#endif +#ifdef OBJECTSPACE_NORMALMAP +uniform normalMatrix: mat4x4f;fn toNormalMatrix(m: mat4x4f)->mat4x4f +{var a00=m[0][0];var a01=m[0][1];var a02=m[0][2];var a03=m[0][3];var a10=m[1][0];var a11=m[1][1];var a12=m[1][2];var a13=m[1][3];var a20=m[2][0]; +var a21=m[2][1];var a22=m[2][2];var a23=m[2][3];var a30=m[3][0]; +var a31=m[3][1];var a32=m[3][2];var a33=m[3][3];var b00=a00*a11-a01*a10;var b01=a00*a12-a02*a10;var b02=a00*a13-a03*a10;var b03=a01*a12-a02*a11;var b04=a01*a13-a03*a11;var b05=a02*a13-a03*a12;var b06=a20*a31-a21*a30;var b07=a20*a32-a22*a30;var b08=a20*a33-a23*a30;var b09=a21*a32-a22*a31;var b10=a21*a33-a23*a31;var b11=a22*a33-a23*a32;var det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;var mi=mat4x4( +(a11*b11-a12*b10+a13*b09)/det, +(a02*b10-a01*b11-a03*b09)/det, +(a31*b05-a32*b04+a33*b03)/det, +(a22*b04-a21*b05-a23*b03)/det, +(a12*b08-a10*b11-a13*b07)/det, +(a00*b11-a02*b08+a03*b07)/det, +(a32*b02-a30*b05-a33*b01)/det, +(a20*b05-a22*b02+a23*b01)/det, +(a10*b10-a11*b08+a13*b06)/det, +(a01*b08-a00*b10-a03*b06)/det, +(a30*b04-a31*b02+a33*b00)/det, +(a21*b02-a20*b04-a23*b00)/det, +(a11*b07-a10*b09-a12*b06)/det, +(a00*b09-a01*b07+a02*b06)/det, +(a31*b01-a30*b03-a32*b00)/det, +(a20*b03-a21*b01+a22*b00)/det);return mat4x4(mi[0][0],mi[1][0],mi[2][0],mi[3][0], +mi[0][1],mi[1][1],mi[2][1],mi[3][1], +mi[0][2],mi[1][2],mi[2][2],mi[3][2], +mi[0][3],mi[1][3],mi[2][3],mi[3][3]);} +#endif +fn perturbNormalBase(cotangentFrame: mat3x3f,normal: vec3f,scale: f32)->vec3f +{var output=normal; +#ifdef NORMALXYSCALE +output=normalize(output* vec3f(scale,scale,1.0)); +#endif +return normalize(cotangentFrame*output);} +fn perturbNormal(cotangentFrame: mat3x3f,textureSample: vec3f,scale: f32)->vec3f +{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);} +fn cotangent_frame(normal: vec3f,p: vec3f,uv: vec2f,tangentSpaceParams: vec2f)->mat3x3f +{var dp1: vec3f=dpdx(p);var dp2: vec3f=dpdy(p);var duv1: vec2f=dpdx(uv);var duv2: vec2f=dpdy(uv);var dp2perp: vec3f=cross(dp2,normal);var dp1perp: vec3f=cross(normal,dp1);var tangent: vec3f=dp2perp*duv1.x+dp1perp*duv2.x;var bitangent: vec3f=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;var det: f32=max(dot(tangent,tangent),dot(bitangent,bitangent));var invmax: f32=select(inverseSqrt(det),0.0,det==0.0);return mat3x3f(tangent*invmax,bitangent*invmax,normal);} +#endif +`; +// Sideeffect +if (!ShaderStore.IncludesShadersStoreWGSL[name]) { + ShaderStore.IncludesShadersStoreWGSL[name] = shader; +} +/** @internal */ +export const openpbrNormalMapFragmentMainFunctionsWGSL = { name, shader }; +//# sourceMappingURL=openpbrNormalMapFragmentMainFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map new file mode 100644 index 00000000000..34b5ae01659 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openpbrNormalMapFragmentMainFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentMainFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,uCAAuC,CAAC;AACrD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,yCAAyC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragmentMainFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL)\n#if defined(TANGENT) && defined(NORMAL) \nvarying vTBN0: vec3f;varying vTBN1: vec3f;varying vTBN2: vec3f;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\nuniform normalMatrix: mat4x4f;fn toNormalMatrix(m: mat4x4f)->mat4x4f\n{var a00=m[0][0];var a01=m[0][1];var a02=m[0][2];var a03=m[0][3];var a10=m[1][0];var a11=m[1][1];var a12=m[1][2];var a13=m[1][3];var a20=m[2][0]; \nvar a21=m[2][1];var a22=m[2][2];var a23=m[2][3];var a30=m[3][0]; \nvar a31=m[3][1];var a32=m[3][2];var a33=m[3][3];var b00=a00*a11-a01*a10;var b01=a00*a12-a02*a10;var b02=a00*a13-a03*a10;var b03=a01*a12-a02*a11;var b04=a01*a13-a03*a11;var b05=a02*a13-a03*a12;var b06=a20*a31-a21*a30;var b07=a20*a32-a22*a30;var b08=a20*a33-a23*a30;var b09=a21*a32-a22*a31;var b10=a21*a33-a23*a31;var b11=a22*a33-a23*a32;var det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;var mi=mat4x4(\n(a11*b11-a12*b10+a13*b09)/det,\n(a02*b10-a01*b11-a03*b09)/det,\n(a31*b05-a32*b04+a33*b03)/det,\n(a22*b04-a21*b05-a23*b03)/det,\n(a12*b08-a10*b11-a13*b07)/det,\n(a00*b11-a02*b08+a03*b07)/det,\n(a32*b02-a30*b05-a33*b01)/det,\n(a20*b05-a22*b02+a23*b01)/det,\n(a10*b10-a11*b08+a13*b06)/det,\n(a01*b08-a00*b10-a03*b06)/det,\n(a30*b04-a31*b02+a33*b00)/det,\n(a21*b02-a20*b04-a23*b00)/det,\n(a11*b07-a10*b09-a12*b06)/det,\n(a00*b09-a01*b07+a02*b06)/det,\n(a31*b01-a30*b03-a32*b00)/det,\n(a20*b03-a21*b01+a22*b00)/det);return mat4x4(mi[0][0],mi[1][0],mi[2][0],mi[3][0],\nmi[0][1],mi[1][1],mi[2][1],mi[3][1],\nmi[0][2],mi[1][2],mi[2][2],mi[3][2],\nmi[0][3],mi[1][3],mi[2][3],mi[3][3]);}\n#endif\nfn perturbNormalBase(cotangentFrame: mat3x3f,normal: vec3f,scale: f32)->vec3f\n{var output=normal;\n#ifdef NORMALXYSCALE\noutput=normalize(output* vec3f(scale,scale,1.0));\n#endif\nreturn normalize(cotangentFrame*output);}\nfn perturbNormal(cotangentFrame: mat3x3f,textureSample: vec3f,scale: f32)->vec3f\n{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);}\nfn cotangent_frame(normal: vec3f,p: vec3f,uv: vec2f,tangentSpaceParams: vec2f)->mat3x3f\n{var dp1: vec3f=dpdx(p);var dp2: vec3f=dpdy(p);var duv1: vec2f=dpdx(uv);var duv2: vec2f=dpdy(uv);var dp2perp: vec3f=cross(dp2,normal);var dp1perp: vec3f=cross(normal,dp1);var tangent: vec3f=dp2perp*duv1.x+dp1perp*duv2.x;var bitangent: vec3f=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;var det: f32=max(dot(tangent,tangent),dot(bitangent,bitangent));var invmax: f32=select(inverseSqrt(det),0.0,det==0.0);return mat3x3f(tangent*invmax,bitangent*invmax,normal);}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentMainFunctionsWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertex.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertex.fx new file mode 100644 index 00000000000..504955cd129 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertex.fx @@ -0,0 +1,11 @@ +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + var tbnNormal: vec3f = normalize(normalUpdated); + var tbnTangent: vec3f = normalize(tangentUpdated.xyz); + var tbnBitangent: vec3f = cross(tbnNormal, tbnTangent) * tangentUpdated.w; + var matTemp = mat3x3f(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz) * mat3x3f(tbnTangent, tbnBitangent, tbnNormal); + vertexOutputs.vTBN0 = matTemp[0]; + vertexOutputs.vTBN1 = matTemp[1]; + vertexOutputs.vTBN2 = matTemp[2]; + #endif +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertexDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertexDeclaration.fx new file mode 100644 index 00000000000..11b840ed96f --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapVertexDeclaration.fx @@ -0,0 +1,7 @@ +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) + #if defined(TANGENT) && defined(NORMAL) + varying vTBN0: vec3f; + varying vTBN1: vec3f; + varying vTBN2: vec3f; + #endif +#endif diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 3e29dd60f18..ed7e19321ff 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -35,8 +35,8 @@ #include #include #include -#include -#include +#include +#include #ifdef REFLECTION #include @@ -61,7 +61,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs { // _____________________________ Geometry Information ____________________________ #include - #include + #include #include @@ -205,7 +205,7 @@ var specularColor: vec4f = uniforms.vSpecularColor; #endif // _____________________________ Compute Geometry info _________________________________ - #include + #include // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 8daa3da7b79..2fe060de8bb 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -35,11 +35,11 @@ attribute color: vec4f; #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #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) @@ -62,7 +62,7 @@ varying vPositionW: vec3f; varying vColor: vec4f; #endif -#include +#include #include #include #include[0..maxSimultaneousLights] @@ -206,17 +206,17 @@ fn main(input : VertexInputs) -> FragmentInputs { #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_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.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 +#include // Clip plane #include 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 b28df370c69..661efd4329e 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 @@ -121,39 +121,47 @@ export class PBRMaterialPropertyGridComponent extends React.Component )} - - - - this.switchAmbientMode(state)} - label="Ambient" - texture={material.ambientTexture} - propertyName="ambientTexture" - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} - /> + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + + )} + {material instanceof PBRMaterial && ( + this.switchAmbientMode(state)} + label="Ambient" + texture={material.ambientTexture} + propertyName="ambientTexture" + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} + /> + )} - {material.bumpTexture && ( + {material instanceof PBRMaterial && material.bumpTexture && ( )} - {material.ambientTexture && ( + {material instanceof PBRMaterial && material.ambientTexture && ( { texture.name = `${babylonMaterial.name} (Normal)`; - babylonMaterial.bumpTexture = texture; + if (this.parent.useOpenPBR) { + const mat = babylonMaterial as OpenPBRMaterial; + mat.geometryNormalTexture = texture; + if (material.normalTexture?.scale != undefined && mat.geometryNormalTexture) { + mat.geometryNormalTexture.level = material.normalTexture.scale; + } + } else { + const mat = babylonMaterial as PBRMaterial; + mat.bumpTexture = texture; + if (material.normalTexture?.scale != undefined && mat.bumpTexture) { + mat.bumpTexture.level = material.normalTexture.scale; + } + } }) ); babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem; babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem; - if (material.normalTexture.scale != undefined && babylonMaterial.bumpTexture) { - babylonMaterial.bumpTexture.level = material.normalTexture.scale; - } - babylonMaterial.forceIrradianceInFragment = true; } From cf8143a236c20443e3b3cadbf26008857093a248 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 21 Jul 2025 16:29:45 -0700 Subject: [PATCH 25/45] Remove lightmap from OpenPBR --- .../core/src/Materials/PBR/openPbrMaterial.ts | 98 ------------------- .../ShadersInclude/openPbrUboDeclaration.fx | 2 - .../openpbrFragmentDeclaration.fx | 4 - .../openpbrFragmentSamplersDeclaration.fx | 1 - .../dev/core/src/Shaders/openpbr.fragment.fx | 20 +++- .../dev/core/src/Shaders/openpbr.vertex.fx | 2 - .../ShadersInclude/openPbrUboDeclaration.fx | 2 - .../openpbrFragmentSamplersDeclaration.fx | 2 - .../core/src/ShadersWGSL/openpbr.fragment.fx | 2 - .../core/src/ShadersWGSL/openpbr.vertex.fx | 6 +- 10 files changed, 17 insertions(+), 122 deletions(-) diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 77bfe70a1ad..583049eb770 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -251,12 +251,6 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM 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; @@ -278,7 +272,6 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public LODINREFLECTIONALPHA = false; public GAMMAREFLECTION = false; public RGBDREFLECTION = false; - public LINEARSPECULARREFLECTION = false; public RADIANCEOCCLUSION = false; public HORIZONOCCLUSION = false; @@ -658,20 +651,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public useSpecularWeightFromTextureAlpha = false; - /** - * 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. */ @@ -981,36 +960,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ public _useSpecularWeightFromTextureAlpha = false; - /** - * 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). @@ -1597,12 +1546,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { - if (!this._lightmapTexture.isReadyOrNotBlocking()) { - return false; - } - } - if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) { // This is blocking. if (!this._environmentBRDFTexture.isReady()) { @@ -1691,8 +1634,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public override buildUniformLayout(): void { // Order is important ! const ubo = this._uniformBuffer; - ubo.addUniform("vLightmapInfos", 2); - ubo.addUniform("lightmapMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); ubo.addUniform("vLightingIntensity", 4); @@ -1789,11 +1730,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { - ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level); - BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); - } - if (this.geometryNormalTexture) { if (scene._mirroredCameraPosition) { ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0); @@ -1852,10 +1788,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { if (defines.ENVIRONMENTBRDF) { ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); } - - if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) { - ubo.setTexture("lightmapSampler", this._lightmapTexture); - } } // OIT with depth peeling @@ -1929,10 +1861,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { results.push(this._reflectionTexture); } - if (this._lightmapTexture && this._lightmapTexture.animations && this._lightmapTexture.animations.length > 0) { - results.push(this._lightmapTexture); - } - return results; } @@ -1955,10 +1883,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { activeTextures.push(this._reflectionTexture); } - if (this._lightmapTexture) { - activeTextures.push(this._lightmapTexture); - } - return activeTextures; } @@ -1984,10 +1908,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { return true; } - if (this._lightmapTexture === texture) { - return true; - } - return false; } @@ -2020,7 +1940,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } this._reflectionTexture?.dispose(); - this._lightmapTexture?.dispose(); } this._renderTargets.dispose(); @@ -2115,10 +2034,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { fallbacks.addFallback(fallbackRank++, "USEIRRADIANCEMAP"); } - if (defines.LIGHTMAP) { - fallbacks.addFallback(fallbackRank++, "LIGHTMAP"); - } - if (defines.NORMAL) { fallbacks.addFallback(fallbackRank++, "NORMAL"); } @@ -2173,10 +2088,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { "vFogInfos", "vFogColor", "pointSize", - "vLightmapInfos", "mBones", "normalMatrix", - "lightmapMatrix", "vLightingIntensity", "logarithmicDepthConstant", "vTangentSpaceParams", @@ -2192,7 +2105,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } const samplers = [ - "lightmapSampler", "environmentBrdfSampler", "boneSampler", "morphTargets", @@ -2321,7 +2233,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines["MAINUV" + i] = false; } if (scene.texturesEnabled) { - defines.LIGHTMAPDIRECTUV = 0; if (engine.getCaps().textureLOD) { defines.LODBASEDMICROSFURACE = true; @@ -2347,15 +2258,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index f889a36129f..b1b0f67b147 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -23,8 +23,6 @@ layout(std140, column_major) uniform; // } uniform Material { - vec2 vLightmapInfos; - mat4 lightmapMatrix; vec2 vTangentSpaceParams; vec4 vLightingIntensity; float pointSize; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index 762c207a42b..574c6838ed7 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -42,10 +42,6 @@ uniform vec2 vGeometryOpacityInfos; uniform vec2 vEmissionInfos; #endif -#ifdef LIGHTMAP -uniform vec2 vLightmapInfos; -#endif - #ifdef METALLIC_ROUGHNESS uniform vec2 vBaseMetalRoughInfos; #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index b44f1d73601..0b6e7ac13a5 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -9,7 +9,6 @@ #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 diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 9ff73273a6d..874c6c13e7e 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -143,6 +143,19 @@ void main(void) { // Mopaque-base =mix(Mglossy-diffuse,Ssubsurface,S) whereS =subsurface_weight // Mglossy-diffuse =layer(Sdiffuse,Sgloss) +// Base roughness is modified by the coat layer +// rB′ = mix(rB, min(1, rB^4 + 2rC^4)^1/4 , C) where C = coat_weight (61) in OpenPBR spec + +// Sample specular lobe IBL and analytic lights separately from BRDF for each layer +// - pass in roughness, anisotropy, sample vector (and tangent?). Same code for reflection and refraction. +// - Coat: - one sample - pass in coat_roughness_anisotropy, coat_roughness, geometry_coat_normal +// - Base:- one sample - pass in geometry_normal, specular_roughness, specular_anisotropy +// - Translucent refraction +// - thin-walled refraction - i.e. no refraction +// Sample diffuse lobe IBL and analytic lights separately from BRDF for each layer +// - only Base layer has diffuse lobe +// - pass in base_diffuse_roughness, geometry_normal, base_color +// - Subsurface - refracted/transmitted diffuse - (geometry_thin_walled with subsurface is the same as glTF diffuse transmission) // _____________________________ AO _______________________________ @@ -159,8 +172,6 @@ void main(void) { #endif ); - #include - #ifdef UNLIT vec3 diffuseBase = vec3(1., 1., 1.); #else // !UNLIT @@ -233,6 +244,8 @@ vec4 specularColor = vSpecularColor; // _____________________________ Compute Geometry info _________________________________ #include +// Share code for reflection and refraction +// Pass in values to select between reflection and refraction, diffuse and specular, anisotropic and isotropic // _____________________________ Reflection Info _______________________________________ #ifdef REFLECTION reflectionOutParams reflectionOut; @@ -250,9 +263,6 @@ vec4 specularColor = vSpecularColor; #endif #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) , NdotVUnclamped - #endif - #ifdef LINEARSPECULARREFLECTION - , roughness #endif , reflectionSampler #if defined(NORMAL) && defined(USESPHERICALINVERTEX) diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 8961ec24981..fb6e3f845d4 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -46,7 +46,6 @@ attribute vec4 color; #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) // Output varying vec3 vPositionW; @@ -225,7 +224,6 @@ void main(void) { #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_MATRIXNAME_,ambientOcclusion,_INFONAME_,AmbientOcclusionInfos.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 diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index 65f1c6af73f..c2a119bfa7e 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -1,6 +1,4 @@ -uniform vLightmapInfos: vec2f; -uniform lightmapMatrix: mat4x4f; uniform vTangentSpaceParams: vec2f; uniform vLightingIntensity: vec4f; uniform pointSize: f32; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 78bf8a3c071..947651182d4 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -9,8 +9,6 @@ #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 diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index ed7e19321ff..35c5c6c3a7c 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -132,8 +132,6 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif ); - #include - #ifdef UNLIT var diffuseBase: vec3f = vec3f(1., 1., 1.); #else diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 2fe060de8bb..a7ad5006f1e 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -42,7 +42,6 @@ attribute color: vec4f; #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail) -#include(_DEFINENAME_,LIGHTMAP,_VARYINGNAME_,Lightmap) // Output varying vPositionW: vec3f; @@ -209,12 +208,11 @@ fn main(input : VertexInputs) -> FragmentInputs { #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.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_,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 From 844819167c34ba9c956c2bbdb6062a5d63aaa9d2 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 30 Jul 2025 13:16:24 -0700 Subject: [PATCH 26/45] Starting to refactor glsl shaders for OpenPBR --- .vscode/settings.json | 2 +- .../core/src/Materials/PBR/openPbrMaterial.ts | 212 ++++----- .../src/Materials/materialHelper.functions.ts | 1 + .../IBLShadows/iblShadowsPluginMaterial.ts | 20 +- .../ShadersInclude/openPbrUboDeclaration.fx | 12 +- .../ShadersInclude/openpbrBaseLayerData.fx | 138 ++++++ .../openpbrBlockAlbedoOpacity.fx | 115 ----- .../openpbrBlockFinalColorComposition.fx | 33 -- .../openpbrBlockFinalLitComponents.fx | 69 --- .../openpbrBlockGeometryInfo.fx | 35 -- .../ShadersInclude/openpbrBlockReflectance.fx | 36 -- .../openpbrBlockReflectivity.fx | 135 ------ .../ShadersInclude/openpbrCoatLayerData.fx | 65 +++ .../openpbrConductorReflectance.fx | 20 + .../openpbrDielectricReflectance.fx | 53 +++ .../openpbrDirectLightingDiffuse.fx | 30 ++ .../openpbrDirectLightingInit.fx | 81 ++++ .../openpbrDirectLightingShadow.fx | 133 ++++++ .../openpbrDirectLightingSpecular.fx | 41 ++ .../openpbrFragmentDeclaration.fx | 7 +- .../openpbrFragmentSamplersDeclaration.fx | 3 + .../ShadersInclude/openpbrGeometryInfo.fx | 37 ++ .../ShadersInclude/openpbrIblFunctions.fx | 236 ++++++++++ .../openpbrNormalMapFragmentFunctions.fx | 4 + .../openpbrNormalMapFragmentMainFunctions.fx | 2 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 419 +++++++++--------- .../dev/core/src/Shaders/openpbr.vertex.fx | 6 + .../ShadersInclude/openPbrUboDeclaration.fx | 10 + .../openpbrBlockFinalColorComposition.fx | 33 -- .../openpbrBlockFinalLitComponents.fx | 21 +- .../openpbrFragmentSamplersDeclaration.fx | 4 + .../ShadersInclude/openpbrIblFunctions.fx | 176 ++++++++ .../core/src/ShadersWGSL/openpbr.fragment.fx | 4 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 6 + .../pbrMaterialPropertyGridComponent.tsx | 18 +- .../2.0/Extensions/KHR_materials_clearcoat.ts | 8 +- ...enPBR-IBL-F82-Specular-Metal-vs-Weight.png | Bin 0 -> 141630 bytes ...R-IBL-F82-Specular-Roughness-vs-Weight.png | Bin 0 -> 111428 bytes ...enPBR-IBL-Furnace-Test-for-Metal-Rough.png | Bin 0 -> 1599 bytes .../OpenPBR-IBL-Metal-vs-Coat-IOR.png | Bin 0 -> 194426 bytes .../OpenPBR-IBL-Reflectance-with-IOR.png | Bin 0 -> 56791 bytes .../OpenPBR-IBL-Specular-IOR-vs-Coat-IOR.png | Bin 0 -> 142421 bytes ...penPBR-IBL-Specular-IOR-vs-Coat-Weight.png | Bin 0 -> 115904 bytes .../tests/test/visualization/config.json | 40 ++ 44 files changed, 1453 insertions(+), 812 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingShadow.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Metal-vs-Weight.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Roughness-vs-Weight.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Furnace-Test-for-Metal-Rough.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Metal-vs-Coat-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Reflectance-with-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-Weight.png diff --git a/.vscode/settings.json b/.vscode/settings.json index 375867ba018..c2d94cb8798 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,7 +50,7 @@ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.formatOnSave": true, + "editor.formatOnSave": false, "jest.runMode": "on-demand", "typescript.preferences.importModuleSpecifier": "project-relative", "javascript.preferences.importModuleSpecifier": "project-relative" diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 583049eb770..b86081e9a27 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { serialize, expandToProperty, serializeAsTexture, addAccessorsForMaterialProperty } from "../../Misc/decorators"; +import { serialize, expandToProperty, addAccessorsForMaterialProperty } from "../../Misc/decorators"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools"; import type { Nullable } from "../../types"; import { Scene } from "../../scene"; @@ -10,7 +10,7 @@ import { PBRBaseMaterial } from "./pbrBaseMaterial"; import { RegisterClass } from "../../Misc/typeStore"; import { Material } from "../material"; import { SerializationHelper } from "../../Misc/decorators.serialization"; - +import type { Engine } from "../../Engines/engine"; import type { AbstractMesh } from "../../Meshes/abstractMesh"; import type { Effect, IEffectCreationOptions } from "../../Materials/effect"; import { MaterialDefines } from "../materialDefines"; @@ -229,9 +229,7 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public REFLECTIVITYDIRECTUV = 0; public SPECULARTERM = false; - public MICROSURFACEFROMREFLECTIVITYMAP = false; - public MICROSURFACEAUTOMATIC = false; - public LODBASEDMICROSFURACE = false; + public LODBASEDMICROSFURACE = true; public METALLICWORKFLOW = true; public ROUGHNESSSTOREINMETALMAPALPHA = false; @@ -436,7 +434,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { 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); + private _baseWeight: Property = new Property("base_weight", 1, "vBaseWeight", 1); /** * Base Weight is a multiplier on the diffuse and metal lobes. @@ -555,6 +553,69 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _baseMetalRoughTexture: Sampler = new Sampler("base_metalness_specular_roughness", "baseMetalRough", "METALLIC_ROUGHNESS"); + /** + * Defines the amount of clear coat on the surface. + * See OpenPBR's specs for coat_weight + */ + public coatWeight: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatWeight") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatWeight: Property = new Property("coat_weight", 0.0, "vCoatWeight", 1, 0); + + /** + * Coat weight texture. + * See OpenPBR's specs for coat_weight + */ + public coatWeightTexture: Nullable; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatWeightTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatWeightTexture: Sampler = new Sampler("coat_weight", "coatWeight", "COAT_WEIGHT"); + + /** + * Defines the color of the clear coat on the surface. + * See OpenPBR's specs for coat_color + */ + public coatColor: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatColor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatColor: Property = new Property("coat_color", Color3.White(), "vCoatColor", 3, 0); + + /** + * Color of the clear coat. + * See OpenPBR's specs for coat_color + */ + public coatColorTexture: Nullable; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatColorTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatColorTexture: Sampler = new Sampler("coat_color", "coatColor", "COAT_COLOR"); + + /** + * Defines the roughness of the clear coat on the surface. + * See OpenPBR's specs for coat_roughness + */ + public coatRoughness: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatRoughness") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatRoughness: Property = new Property("coat_roughness", 0.0, "vCoatRoughness", 1, 0); + + /** + * Roughness of the clear coat. + * See OpenPBR's specs for coat_roughness + */ + public coatRoughnessTexture: Nullable; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatRoughnessTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatRoughnessTexture: Sampler = new Sampler("coat_roughness", "coatRoughness", "COAT_ROUGHNESS"); + + /** + * Defines the IOR of the clear coat on the surface. + * See OpenPBR's specs for coat_ior + */ + public coatIor: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatIor") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatIor: Property = new Property("coat_ior", 1.5, "vCoatIor", 1, 0); + /** * Defines the normal of the material's geometry. * See OpenPBR's specs for geometry_normal @@ -637,13 +698,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @expandToProperty("_markAllSubMeshesAsTexturesDirty") public environmentIntensity: number = 1.0; - /** - * 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. */ @@ -672,13 +726,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @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. */ @@ -693,14 +740,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @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. @@ -948,10 +987,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, 1.0); /** - * Stores the reflection values in a texture. + * Stores the radiance (and, possibly, irradiance) values in a texture. * @internal */ - public _reflectionTexture: Nullable = null; + public _radianceTexture: Nullable = null; /** * Specifies that only the A channel from _metallicReflectanceTexture should be used. @@ -980,38 +1019,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ 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. @@ -1019,13 +1032,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ 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 @@ -1222,6 +1228,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ constructor(name: string, scene?: Scene, forceGLSL = false) { super(name, scene, undefined, forceGLSL || PBRBaseMaterial.ForceGLSL); + // TODO: Check if we're running WebGL 2.0 or above + if (scene && !scene?.getEngine().isWebGPU && (scene.getEngine() as Engine).webGLVersion < 2) { + Logger.Error("OpenPBRMaterial: WebGL 2.0 or above is required for this material."); + } // Setup the default processing configuration to the scene. this._attachImageProcessingConfiguration(null); @@ -1229,8 +1239,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this.getRenderTargetTextures = (): SmartArray => { this._renderTargets.reset(); - if (MaterialFlags.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { - this._renderTargets.push(this._reflectionTexture); + if (MaterialFlags.ReflectionTextureEnabled && this._radianceTexture && this._radianceTexture.isRenderTarget) { + this._renderTargets.push(this._radianceTexture); } this._eventInfo.renderTargets = this._renderTargets; @@ -1299,6 +1309,13 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._specularRoughness; this._specularIor; this._baseMetalRoughTexture; + this._coatWeight; + this._coatWeightTexture; + this._coatColor; + this._coatColorTexture; + this._coatRoughness; + this._coatRoughnessTexture; + this._coatIor; this._geometryNormalTexture; this._geometryOpacity; this._geometryOpacityTexture; @@ -1311,7 +1328,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { * Gets a boolean indicating that current material needs to register RTT */ public override get hasRenderTargetTextures(): boolean { - if (MaterialFlags.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { + if (MaterialFlags.ReflectionTextureEnabled && this._radianceTexture && this._radianceTexture.isRenderTarget) { return true; } @@ -1529,18 +1546,18 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - const reflectionTexture = this._getReflectionTexture(); - if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { - if (!reflectionTexture.isReadyOrNotBlocking()) { + const radianceTexture = this._getRadianceTexture(); + if (radianceTexture && MaterialFlags.ReflectionTextureEnabled) { + if (!radianceTexture.isReadyOrNotBlocking()) { return false; } - if (reflectionTexture.irradianceTexture) { - if (!reflectionTexture.irradianceTexture.isReadyOrNotBlocking()) { + if (radianceTexture.irradianceTexture) { + if (!radianceTexture.irradianceTexture.isReadyOrNotBlocking()) { return false; } } else { // Not ready until spherical are ready too. - if (!reflectionTexture.sphericalPolynomial && reflectionTexture.getInternalTexture()?._sphericalPolynomialPromise) { + if (!radianceTexture.sphericalPolynomial && radianceTexture.getInternalTexture()?._sphericalPolynomialPromise) { return false; } } @@ -1712,11 +1729,11 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // Bones BindBonesParameters(mesh, this._activeEffect, this.prePassConfiguration); - let reflectionTexture: Nullable = null; + let radianceTexture: Nullable = null; const ubo = this._uniformBuffer; if (mustRebind) { this.bindViewProjection(effect); - reflectionTexture = this._getReflectionTexture(); + radianceTexture = this._getRadianceTexture(); if (!ubo.useUbo || !this.isFrozen || !ubo.isSync || subMesh._drawWrapper._forceRebindOnNextCall) { // Texture uniforms @@ -1739,7 +1756,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - BindIBLParameters(scene, defines, ubo, reflectionTexture, this.realTimeFiltering, true, true, true, true, true, this._reflectionColor); + BindIBLParameters(scene, defines, ubo, radianceTexture, this.realTimeFiltering, true, true, true, true, true, Color3.White()); // Point size if (this.pointsCloud) { @@ -1783,7 +1800,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - BindIBLSamplers(scene, defines, ubo, reflectionTexture, this.realTimeFiltering); + BindIBLSamplers(scene, defines, ubo, radianceTexture, this.realTimeFiltering); if (defines.ENVIRONMENTBRDF) { ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture); @@ -1813,7 +1830,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } // View - if ((scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) || reflectionTexture || mesh.receiveShadows || defines.PREPASS) { + if ((scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) || radianceTexture || mesh.receiveShadows || defines.PREPASS) { this.bindView(effect); } @@ -1857,8 +1874,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._reflectionTexture && this._reflectionTexture.animations && this._reflectionTexture.animations.length > 0) { - results.push(this._reflectionTexture); + if (this._radianceTexture && this._radianceTexture.animations && this._radianceTexture.animations.length > 0) { + results.push(this._radianceTexture); } return results; @@ -1879,8 +1896,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._reflectionTexture) { - activeTextures.push(this._reflectionTexture); + if (this._radianceTexture) { + activeTextures.push(this._radianceTexture); } return activeTextures; @@ -1904,7 +1921,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - if (this._reflectionTexture === texture) { + if (this._radianceTexture === texture) { return true; } @@ -1939,7 +1956,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { sampler.value?.dispose(); } - this._reflectionTexture?.dispose(); + this._radianceTexture?.dispose(); } this._renderTargets.dispose(); @@ -1955,9 +1972,9 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { * 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; + private _getRadianceTexture(): Nullable { + if (this._radianceTexture) { + return this._radianceTexture; } return this.getScene().environmentTexture; @@ -2104,15 +2121,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { uniforms.push(uniformName); } - const samplers = [ - "environmentBrdfSampler", - "boneSampler", - "morphTargets", - "oitDepthSampler", - "oitFrontColorSampler", - "areaLightsLTC1Sampler", - "areaLightsLTC2Sampler", - ]; + const samplers = ["environmentBrdfSampler", "boneSampler", "morphTargets", "oitDepthSampler", "oitFrontColorSampler", "areaLightsLTC1Sampler", "areaLightsLTC2Sampler"]; for (const key in this._samplersList) { const sampler = this._samplersList[key]; @@ -2233,11 +2242,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines["MAINUV" + i] = false; } if (scene.texturesEnabled) { - - 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]; @@ -2249,14 +2253,14 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - const reflectionTexture = this._getReflectionTexture(); + const radianceTexture = this._getRadianceTexture(); 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); + PrepareDefinesForIBL(scene, radianceTexture, defines, this.realTimeFiltering, this.realTimeFilteringQuality, !useSHInFragment); if (MaterialFlags.SpecularTextureEnabled) { if (this._baseMetalRoughTexture) { @@ -2297,8 +2301,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { } } - defines.SPECULAROVERALPHA = this._useSpecularOverAlpha; - if (this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_STANDARD) { defines.USEPHYSICALLIGHTFALLOFF = false; defines.USEGLTFLIGHTFALLOFF = false; @@ -2310,8 +2312,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { defines.USEGLTFLIGHTFALLOFF = false; } - defines.RADIANCEOVERALPHA = this._useRadianceOverAlpha; - if (!this.backFaceCulling && this._twoSidedLighting) { defines.TWOSIDEDLIGHTING = true; } else { diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index 5d7f718e7d3..56201265756 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -22,6 +22,7 @@ import type { IColor3Like } from "core/Maths"; import { MaterialFlags } from "./materialFlags"; import { Texture } from "./Textures/texture"; import type { CubeTexture } from "./Textures/cubeTexture"; +import { Color3 } from "core/Maths/math.color"; // Temps const TempFogColor: IColor3Like = { r: 0, g: 0, b: 0 }; diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts index 409e699f3ae..d5f886cbb99 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts @@ -169,16 +169,16 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #ifdef REFLECTION #ifdef COLORED_IBL_SHADOWS var shadowValue: vec3f = computeIndirectShadow(); - finalIrradiance *= shadowValue; - finalRadianceScaled *= mix(vec3f(1.0), shadowValue, roughness); + slab_diffuse *= shadowValue; + slab_glossy *= mix(vec3f(1.0), shadowValue, alphaG); #else var shadowValue: vec2f = computeIndirectShadow(); - finalIrradiance *= vec3f(shadowValue.x); - finalRadianceScaled *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness)); + slab_diffuse *= vec3f(shadowValue.x); + slab_glossy *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, alphaG)); #endif #endif #else - finalDiffuse *= computeIndirectShadow().x; + slab_diffuse *= computeIndirectShadow().x; #endif #endif `; @@ -247,16 +247,16 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #ifdef REFLECTION #ifdef COLORED_IBL_SHADOWS vec3 shadowValue = computeIndirectShadow(); - finalIrradiance.rgb *= shadowValue.rgb; - finalRadianceScaled *= mix(vec3(1.0), shadowValue.rgb, roughness); + slab_diffuse.rgb *= shadowValue.rgb; + slab_glossy *= mix(vec3(1.0), shadowValue.rgb, alphaG); #else vec2 shadowValue = computeIndirectShadow(); - finalIrradiance *= shadowValue.x; - finalRadianceScaled *= mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness); + slab_diffuse *= shadowValue.x; + slab_glossy *= mix(pow(shadowValue.y, 4.0), shadowValue.x, alphaG); #endif #endif #else - finalDiffuse *= computeIndirectShadow().x; + slab_diffuse *= computeIndirectShadow().x; #endif #endif `; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index b1b0f67b147..ebcbdd8e31d 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -60,11 +60,15 @@ uniform Material { vec3 vSphericalYZ; vec3 vSphericalZX; - float baseWeight; + float vBaseWeight; vec4 vBaseColor; float vBaseDiffuseRoughness; vec4 vReflectanceInfo; vec4 vSpecularColor; + float vCoatWeight; + vec3 vCoatColor; + float vCoatRoughness; + float vCoatIor; vec3 vEmissionColor; vec2 vBaseWeightInfos; @@ -79,6 +83,12 @@ uniform Material { mat4 specularColorMatrix; vec2 vBaseMetalRoughInfos; mat4 baseMetalRoughMatrix; + vec2 vCoatWeightInfos; + mat4 coatWeightMatrix; + vec2 vCoatColorInfos; + mat4 coatColorMatrix; + vec2 vCoatRoughnessInfos; + mat4 coatRoughnessMatrix; vec2 vGeometryNormalInfos; mat4 geometryNormalMatrix; vec2 vGeometryOpacityInfos; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx new file mode 100644 index 00000000000..d6d18b2ef8e --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx @@ -0,0 +1,138 @@ +// This code reads uniforms and samples textures to fill up the base and specular +// layer properties for OpenPBR + +// Base Layer Properties +// We don't include base_weight in our initial variables because it is multiplied +// into the base_color in this code snippet. +vec3 base_color = vec3(0.8); +float base_metalness = 0.0; +float base_diffuse_roughness = 0.0; + +// Specular Layer Properties +float specular_weight = 1.0; +float specular_roughness = 0.3; +vec3 specular_color = vec3(1.0); +float specular_roughness_anisotropy = 0.0; +float specular_ior = 1.5; +float alpha = 1.0; + +// Sample Base Layer properties from textures +#ifdef BASE_WEIGHT + vec4 baseWeightFromTexture = texture2D(baseWeightSampler, vBaseWeightUV + uvOffset); +#endif + +#ifdef BASE_COLOR + vec4 baseColorFromTexture = texture2D(baseColorSampler, vBaseColorUV + uvOffset); +#endif + +#ifdef METALLIC_ROUGHNESS + vec4 metallicRoughnessFromTexture = texture2D(baseMetalRoughSampler, vBaseMetalRoughUV + uvOffset); +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + float baseDiffuseRoughnessFromTexture = texture2D(baseDiffuseRoughnessSampler, vBaseDiffuseRoughnessUV + uvOffset).r; +#endif + +#ifdef GEOMETRY_OPACITY + vec4 opacityFromTexture = texture2D(opacitySampler, vOpacityUV + uvOffset); +#endif + +#ifdef DECAL + vec4 decalFromTexture = texture2D(decalSampler, vDecalUV + uvOffset); +#endif + +#ifdef SPECULAR_COLOR + vec4 specularColorFromTexture = texture2D(specularColorSampler, vSpecularColorUV + uvOffset); + #ifdef SPECULAR_COLOR_GAMMA + specularColorFromTexture = toLinearSpace(specularColorFromTexture.rgb); + #endif +#endif + +#ifdef SPECULAR_WEIGHT + vec4 specularWeightFromTexture = texture2D(specularWeightSampler, vSpecularWeightUV + uvOffset); +#endif + +// Initalize base layer properties from uniforms +base_color = vBaseColor.rgb; +#if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) + base_color *= vColor.rgb; +#endif +#if defined(VERTEXALPHA) || defined(INSTANCESCOLOR) && defined(INSTANCES) + alpha *= vColor.a; +#endif +base_color *= vec3(vBaseWeight); +alpha = vBaseColor.a; +base_metalness = vReflectanceInfo.x; +base_diffuse_roughness = vBaseDiffuseRoughness; +specular_roughness = vReflectanceInfo.y; +specular_color = vSpecularColor.rgb; +specular_weight = vReflectanceInfo.a; +specular_ior = vReflectanceInfo.z; + +// Apply texture values to base layer properties + +#ifdef BASE_COLOR + #if defined(ALPHAFROMALBEDO) || defined(ALPHATEST) + alpha *= baseColorFromTexture.a; + #endif + + #ifdef BASE_COLOR_GAMMA + base_color *= toLinearSpace(baseColorFromTexture.rgb); + #else + base_color *= baseColorFromTexture.rgb; + #endif + + base_color *= vBaseColorInfos.y; +#endif + +#ifdef BASE_WEIGHT + base_color *= baseWeightFromTexture.r; +#endif + +// _____________________________ Alpha Information _______________________________ +#ifdef GEOMETRY_OPACITY + alpha *= opacityFromTexture.a; + alpha *= vGeometryOpacityInfos.y; +#endif + +#ifdef ALPHATEST + #if DEBUGMODE != 88 + if (alpha < ALPHATESTVALUE) + discard; + #endif + + #ifndef ALPHABLEND + // Prevent to blend with the canvas. + alpha = 1.0; + #endif +#endif + +#ifdef METALLIC_ROUGHNESS + base_metalness *= metallicRoughnessFromTexture.b; + specular_roughness *= metallicRoughnessFromTexture.g; +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + base_diffuse_roughness *= baseDiffuseRoughnessFromTexture * vBaseDiffuseRoughnessInfos.y; +#endif + +#ifdef SPECULAR_COLOR + specular_color *= specularColorFromTexture.rgb; +#endif + +#ifdef SPECULAR_WEIGHT + // 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 + specular_weight *= specularWeightFromTexture.a; + #else + specular_weight *= specularWeightFromTexture.r; + #endif +#endif + +#ifdef DETAIL + float detailRoughness = mix(0.5, detailColor.b, vDetailInfos.w); + float loLerp = mix(0., specular_roughness, detailRoughness * 2.); + float hiLerp = mix(specular_roughness, 1., (detailRoughness - 0.5) * 2.); + specular_roughness = mix(loLerp, hiLerp, step(detailRoughness, 0.5)); +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx deleted file mode 100644 index 1053198bdf4..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAlbedoOpacity.fx +++ /dev/null @@ -1,115 +0,0 @@ -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 deleted file mode 100644 index aa96e0ca8cb..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalColorComposition.fx +++ /dev/null @@ -1,33 +0,0 @@ -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 deleted file mode 100644 index 8dcb78aa4f0..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockFinalLitComponents.fx +++ /dev/null @@ -1,69 +0,0 @@ -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/openpbrBlockGeometryInfo.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx deleted file mode 100644 index 6cdf2244cfd..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockGeometryInfo.fx +++ /dev/null @@ -1,35 +0,0 @@ -float NdotVUnclamped = dot(normalW, viewDirectionW); -// The order 1886 page 3. -float NdotV = absEps(NdotVUnclamped); -float alphaG = convertRoughnessToAverageSlope(roughness); -vec2 AARoughnessFactors = getAARoughnessFactors(normalW.xyz); - -#ifdef SPECULARAA - // Adapt linear roughness (alphaG) to geometric curvature of the current pixel. - alphaG += AARoughnessFactors.y; -#endif - -#if defined(ENVIRONMENTBRDF) - // BRDF Lookup - vec3 environmentBrdf = getBRDFLookup(NdotV, roughness); -#endif - -#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) - #ifdef RADIANCEOCCLUSION - #ifdef AMBIENTINGRAYSCALE - float ambientMonochrome = aoOut.ambientOcclusionColor.r; - #else - float ambientMonochrome = getLuminance(aoOut.ambientOcclusionColor); - #endif - - float seo = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped); - #endif - - #ifdef HORIZONOCCLUSION - #ifdef GEOMETRY_NORMAL - #ifdef REFLECTIONMAP_3D - float eho = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); - #endif - #endif - #endif -#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx deleted file mode 100644 index d41591fee1f..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectance.fx +++ /dev/null @@ -1,36 +0,0 @@ -#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 GEOMETRY_NORMAL - #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 deleted file mode 100644 index eed66449874..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockReflectivity.fx +++ /dev/null @@ -1,135 +0,0 @@ -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/openpbrCoatLayerData.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx new file mode 100644 index 00000000000..081db0426d4 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx @@ -0,0 +1,65 @@ +// This code reads uniforms and samples textures to fill up the coat +// layer properties for OpenPBR + +float coat_weight = 0.0; +vec3 coat_color = vec3(1.0); +float coat_roughness = 0.0; +float coat_roughness_anisotropy = 0.0; +float coat_ior = 1.6; +float coat_darkening = 1.0; + +// Sample Coat Layer properties from textures +#ifdef COAT_WEIGHT + vec4 coatWeightFromTexture = texture2D(coatWeightSampler, vCoatWeightUV + uvOffset); +#endif + +#ifdef COAT_COLOR + vec4 coatColorFromTexture = texture2D(coatColorSampler, vCoatColorUV + uvOffset); +#endif + +#ifdef COAT_ROUGHNESS + vec4 coatRoughnessFromTexture = texture2D(coatRoughnessSampler, vCoatRoughnessUV + uvOffset); +#endif + +#ifdef COAT_ROUGHNESS_ANISOTROPY + float coatRoughnessAnisotropyFromTexture = texture2D(coatRoughnessAnisotropySampler, vCoatRoughnessAnisotropyUV + uvOffset).r; +#endif + +#ifdef COAT_DARKENING + vec4 coatDarkeningFromTexture = texture2D(coatDarkeningSampler, vCoatDarkeningUV + uvOffset); +#endif + +// Initalize coat layer properties from uniforms +coat_color = vCoatColor.rgb; +coat_weight = vCoatWeight; +coat_roughness = vCoatRoughness; +// coat_roughness_anisotropy = vCoatRoughnessAnisotropy; +coat_ior = vCoatIor; +// coat_darkening = vCoatDarkening; + +// Apply texture values to coat layer properties +#ifdef COAT_WEIGHT + coat_weight *= coatWeightFromTexture.r; +#endif + +#ifdef COAT_COLOR + #ifdef COAT_COLOR_GAMMA + coat_color *= toLinearSpace(coatColorFromTexture.rgb); + #else + coat_color *= coatColorFromTexture.rgb; + #endif + + coat_color *= vCoatColorInfos.y; +#endif + +#ifdef COAT_ROUGHNESS + coat_roughness *= coatRoughnessFromTexture.r; +#endif + +#ifdef COAT_ROUGHNESS_ANISOTROPY + coat_roughness_anisotropy *= coatRoughnessAnisotropyFromTexture; +#endif + +#ifdef COAT_DARKENING + coat_darkening *= coatDarkeningFromTexture.r; +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx new file mode 100644 index 00000000000..62c15e411e2 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx @@ -0,0 +1,20 @@ +struct conductorReflectanceOutParams +{ + vec3 F0; + vec3 F90; +}; + +#define pbr_inline +conductorReflectanceOutParams conductorReflectance(in vec3 baseColor, in vec3 specularColor, in float specularWeight) +{ + conductorReflectanceOutParams outParams; + + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + outParams.F0 = baseColor * specularWeight; + outParams.F90 = specularColor * specularWeight; + #else + outParams.F0 = baseColor; + outParams.F90 = vec3(1.0); + #endif + return outParams; +} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx new file mode 100644 index 00000000000..f0afbc61f5b --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx @@ -0,0 +1,53 @@ +struct dielectricReflectanceOutParams +{ + float F0; + float F90; + vec3 coloredF0; + vec3 coloredF90; +}; + +#define pbr_inline +dielectricReflectanceOutParams dielectricReflectance( + in float insideIOR, in float outsideIOR, in vec3 specularColor, in float specularWeight +) +{ + dielectricReflectanceOutParams outParams; + + float dielectricF0 = pow((insideIOR - outsideIOR) / (insideIOR + outsideIOR), 2.0); + + // 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.F0 = dielectricF0 * maxF0 * specularWeight; + #else + outParams.F0 = dielectricF0 * specularWeight; + #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 * (insideIOR - 1.0), 0.0, 1.0); + outParams.F90 = f90Scale * specularWeight; + + // 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 layer below. The non-coloured F0 will be used for this (see below). + outParams.coloredF0 = vec3(dielectricF0 * specularWeight) * specularColor.rgb; + + // 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(f90Scale) * specularWeight; + #else + // In glTF, the F90 is white for dielectrics. + vec3 dielectricColorF90 = vec3(f90Scale) * specularWeight; + #endif + outParams.coloredF90 = dielectricColorF90; + + return outParams; +} diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx new file mode 100644 index 00000000000..6ad4829f021 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx @@ -0,0 +1,30 @@ +#ifdef LIGHT{X} + vec4 diffuse{X} = light{X}.vLightDiffuse; + + // Diffuse contribution + #ifdef SS_TRANSLUCENCY + info{X}.diffuseTransmission = vec3(0.0); + #endif + + #ifdef HEMILIGHT{X} + info{X}.diffuse = computeHemisphericDiffuseLighting(preInfo{X}, diffuse{X}.rgb, light{X}.vLightGround); + #elif defined(AREALIGHT{X}) + info{X}.diffuse = computeAreaDiffuseLighting(preInfo{X}, diffuse{X}.rgb); + #else + info{X}.diffuse = computeDiffuseLighting(preInfo{X}, diffuse{X}.rgb); + #endif + + #ifdef PROJECTEDLIGHTTEXTURE{X} + info{X}.diffuse *= computeProjectionTextureDiffuseLighting(projectionLightTexture{X}, textureProjectionMatrix{X}, vPositionW); + #endif + + numLights += 1.0; + + #ifndef SHADOWONLY + #ifdef SHADOWCSMDEBUG{X} + baseDiffuseDirectLight += info{X}.diffuse * shadowDebug{X}; + #else + baseDiffuseDirectLight += info{X}.diffuse * shadow{X}; + #endif + #endif +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx new file mode 100644 index 00000000000..f82a624f71d --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx @@ -0,0 +1,81 @@ +#ifdef LIGHT{X} + preLightingInfo preInfo{X}; + lightingInfo info{X}; + float shadow{X} = 1.; + #if defined(SHADOWONLY) || defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}) + //No light calculation + #else + + #define CUSTOM_LIGHT{X}_COLOR // Use to modify light color. Currently only supports diffuse. + + // Compute Pre Lighting infos + #ifdef SPOTLIGHT{X} + preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + #elif defined(POINTLIGHT{X}) + preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + #elif defined(HEMILIGHT{X}) + preInfo{X} = computeHemisphericPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + #elif defined(DIRLIGHT{X}) + preInfo{X} = computeDirectionalPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + #elif defined(AREALIGHT{X}) && defined(AREALIGHTSUPPORTED) + preInfo{X} = computeAreaPreLightingInfo(areaLightsLTC1Sampler, areaLightsLTC2Sampler, viewDirectionW, normalW, vPositionW, light{X}.vLightData, light{X}.vLightWidth.xyz, light{X}.vLightHeight.xyz, specular_roughness); + #endif + + preInfo{X}.NdotV = baseGeoInfo.NdotV; + + // Compute Attenuation infos + #ifdef SPOTLIGHT{X} + #ifdef LIGHT_FALLOFF_GLTF{X} + preInfo{X}.attenuation = computeDistanceLightFalloff_GLTF(preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.y); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_GLTF(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightFalloff.z, light{X}.vLightFalloff.w); + #endif + #elif defined(LIGHT_FALLOFF_PHYSICAL{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Physical(preInfo{X}.lightDistanceSquared); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_Physical(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w); + #endif + #elif defined(LIGHT_FALLOFF_STANDARD{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Standard(preInfo{X}.lightOffset, light{X}.vLightFalloff.x); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_Standard(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w, light{X}.vLightData.w); + #endif + #else + preInfo{X}.attenuation = computeDistanceLightFalloff(preInfo{X}.lightOffset, preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.x, light{X}.vLightFalloff.y); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w, light{X}.vLightData.w, light{X}.vLightFalloff.z, light{X}.vLightFalloff.w); + #endif + #endif + #elif defined(POINTLIGHT{X}) + #ifdef LIGHT_FALLOFF_GLTF{X} + preInfo{X}.attenuation = computeDistanceLightFalloff_GLTF(preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.y); + #elif defined(LIGHT_FALLOFF_PHYSICAL{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Physical(preInfo{X}.lightDistanceSquared); + #elif defined(LIGHT_FALLOFF_STANDARD{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Standard(preInfo{X}.lightOffset, light{X}.vLightFalloff.x); + #else + preInfo{X}.attenuation = computeDistanceLightFalloff(preInfo{X}.lightOffset, preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.x, light{X}.vLightFalloff.y); + #endif + #else + preInfo{X}.attenuation = 1.0; + #endif + + // Simulates Light radius for diffuse and spec term + // clear coat is using a dedicated roughness + #if defined(HEMILIGHT{X}) || defined(AREALIGHT{X}) + preInfo{X}.roughness = specular_roughness; + #else + preInfo{X}.roughness = adjustRoughnessFromLightProperties(specular_roughness, light{X}.vLightSpecular.a, preInfo{X}.lightDistance); + #endif + preInfo{X}.diffuseRoughness = base_diffuse_roughness; + preInfo{X}.surfaceAlbedo = base_color.rgb; + #endif +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingShadow.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingShadow.fx new file mode 100644 index 00000000000..1eb866fbc49 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingShadow.fx @@ -0,0 +1,133 @@ +#ifdef LIGHT{X} + #ifdef SHADOW{X} + #ifdef SHADOWCSM{X} + for (int i = 0; i < SHADOWCSMNUM_CASCADES{X}; i++) + { + #ifdef SHADOWCSM_RIGHTHANDED{X} + diff{X} = viewFrustumZ{X}[i] + vPositionFromCamera{X}.z; + #else + diff{X} = viewFrustumZ{X}[i] - vPositionFromCamera{X}.z; + #endif + if (diff{X} >= 0.) { + index{X} = i; + break; + } + } + + #ifdef SHADOWCSMUSESHADOWMAXZ{X} + if (index{X} >= 0) + #endif + { + #if defined(SHADOWPCF{X}) + #if defined(SHADOWLOWQUALITY{X}) + shadow{X} = computeShadowWithCSMPCF1(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #elif defined(SHADOWMEDIUMQUALITY{X}) + shadow{X} = computeShadowWithCSMPCF3(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #else + shadow{X} = computeShadowWithCSMPCF5(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWPCSS{X}) + #if defined(SHADOWLOWQUALITY{X}) + shadow{X} = computeShadowWithCSMPCSS16(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #elif defined(SHADOWMEDIUMQUALITY{X}) + shadow{X} = computeShadowWithCSMPCSS32(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #else + shadow{X} = computeShadowWithCSMPCSS64(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #endif + #else + shadow{X} = computeShadowCSM(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + + #ifdef SHADOWCSMDEBUG{X} + shadowDebug{X} = vec3(shadow{X}) * vCascadeColorsMultiplier{X}[index{X}]; + #endif + + #ifndef SHADOWCSMNOBLEND{X} + float frustumLength = frustumLengths{X}[index{X}]; + float diffRatio = clamp(diff{X} / frustumLength, 0., 1.) * cascadeBlendFactor{X}; + if (index{X} < (SHADOWCSMNUM_CASCADES{X} - 1) && diffRatio < 1.) + { + index{X} += 1; + float nextShadow = 0.; + #if defined(SHADOWPCF{X}) + #if defined(SHADOWLOWQUALITY{X}) + nextShadow = computeShadowWithCSMPCF1(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #elif defined(SHADOWMEDIUMQUALITY{X}) + nextShadow = computeShadowWithCSMPCF3(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #else + nextShadow = computeShadowWithCSMPCF5(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWPCSS{X}) + #if defined(SHADOWLOWQUALITY{X}) + nextShadow = computeShadowWithCSMPCSS16(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #elif defined(SHADOWMEDIUMQUALITY{X}) + nextShadow = computeShadowWithCSMPCSS32(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #else + nextShadow = computeShadowWithCSMPCSS64(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w, lightSizeUVCorrection{X}[index{X}], depthCorrection{X}[index{X}], penumbraDarkness{X}); + #endif + #else + nextShadow = computeShadowCSM(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + + shadow{X} = mix(nextShadow, shadow{X}, diffRatio); + #ifdef SHADOWCSMDEBUG{X} + shadowDebug{X} = mix(vec3(nextShadow) * vCascadeColorsMultiplier{X}[index{X}], shadowDebug{X}, diffRatio); + #endif + } + #endif + } + #elif defined(SHADOWCLOSEESM{X}) + #if defined(SHADOWCUBE{X}) + shadow{X} = computeShadowWithCloseESMCube(vPositionW, light{X}.vLightData.xyz, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues); + #else + shadow{X} = computeShadowWithCloseESM(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWESM{X}) + #if defined(SHADOWCUBE{X}) + shadow{X} = computeShadowWithESMCube(vPositionW, light{X}.vLightData.xyz, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues); + #else + shadow{X} = computeShadowWithESM(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWPOISSON{X}) + #if defined(SHADOWCUBE{X}) + shadow{X} = computeShadowWithPoissonSamplingCube(vPositionW, light{X}.vLightData.xyz, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.depthValues); + #else + shadow{X} = computeShadowWithPoissonSampling(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWPCF{X}) + #if defined(SHADOWLOWQUALITY{X}) + shadow{X} = computeShadowWithPCF1(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #elif defined(SHADOWMEDIUMQUALITY{X}) + shadow{X} = computeShadowWithPCF3(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #else + shadow{X} = computeShadowWithPCF5(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #elif defined(SHADOWPCSS{X}) + #if defined(SHADOWLOWQUALITY{X}) + shadow{X} = computeShadowWithPCSS16(vPositionFromLight{X}, vDepthMetric{X}, depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #elif defined(SHADOWMEDIUMQUALITY{X}) + shadow{X} = computeShadowWithPCSS32(vPositionFromLight{X}, vDepthMetric{X}, depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #else + shadow{X} = computeShadowWithPCSS64(vPositionFromLight{X}, vDepthMetric{X}, depthTexture{X}, shadowTexture{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #else + #if defined(SHADOWCUBE{X}) + shadow{X} = computeShadowCube(vPositionW, light{X}.vLightData.xyz, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.depthValues); + #else + shadow{X} = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowTexture{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w); + #endif + #endif + + #ifdef SHADOWONLY + #ifndef SHADOWINUSE + #define SHADOWINUSE + #endif + globalShadow += shadow{X}; + shadowLightCount += 1.0; + #endif + #else + shadow{X} = 1.; + #endif + + aggShadow += shadow{X}; +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx new file mode 100644 index 00000000000..95b6dea8d1a --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx @@ -0,0 +1,41 @@ +#ifdef LIGHT{X} + + // Specular contribution + #ifdef SPECULARTERM + #if AREALIGHT{X} + info{X}.specular = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, specularEnvironmentR0, specularEnvironmentR90); + #else + // For OpenPBR, we use the F82 specular model for metallic materials and mix with the + // usual Schlick lobe. + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + { + vec3 metalFresnel = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.F0, baseConductorReflectance.F90, specular_roughness); + vec3 dielectricFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); + coloredFresnel = mix(dielectricFresnel, metalFresnel, base_metalness); + } + #else + coloredFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); + #endif + { + // The diffuse contribution needs to be decreased by the average Fresnel for the hemisphere. + // We can approximate this with NdotH. + float NdotH = dot(normalW, preInfo{X}.H); + vec3 fresnel = fresnelSchlickGGX(NdotH, vec3(baseDielectricReflectance.F0), baseDielectricReflectance.F90); + info{X}.diffuse *= (vec3(1.0) - fresnel); + } + #ifdef ANISOTROPIC + info{X}.specular = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, specularEnvironmentR0, specularEnvironmentR90, baseGeoInfo.AARoughnessFactors.x, diffuse{X}.rgb); + #else + info{X}.specular = computeSpecularLighting(preInfo{X}, normalW, baseDielectricReflectance.F0, coloredFresnel, specular_roughness, diffuse{X}.rgb); + #endif + + #ifndef SHADOWONLY + #ifdef SHADOWCSMDEBUG{X} + baseSpecularDirectLight += info{X}.specular * shadowDebug{X}; + #else + baseSpecularDirectLight += info{X}.specular * shadow{X}; + #endif + #endif + #endif + #endif +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index 574c6838ed7..7573018c212 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -2,8 +2,9 @@ uniform vec4 vEyePosition; uniform vec3 vReflectionColor; uniform vec4 vBaseColor; -uniform float baseWeight; +uniform float vBaseWeight; uniform float vBaseDiffuseRoughness; +uniform vec4 vCoatColor; // CUSTOM CONTROLS uniform vec4 vLightingIntensity; @@ -46,6 +47,10 @@ uniform vec2 vEmissionInfos; uniform vec2 vBaseMetalRoughInfos; #endif +#ifdef COAT_WEIGHT +uniform vec2 vCoatWeightInfos; +#endif + // Refraction Reflection #if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(SS_REFRACTION) || defined(PREPASS) uniform mat4 view; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 0b6e7ac13a5..bb2cd15c86c 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -4,6 +4,9 @@ #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_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_SAMPLERNAME_,coatWeight) +#include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) +#include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx new file mode 100644 index 00000000000..f7c2a48f0e1 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx @@ -0,0 +1,37 @@ +struct geometryInfoOutParams +{ + float NdotV; + float NdotVUnclamped; + vec3 environmentBrdf; + float horizonOcclusion; +}; + +#define pbr_inline +geometryInfoOutParams geometryInfo( + in vec3 normalW, in vec3 viewDirectionW, in float roughness, in vec3 geometricNormalW +) +{ + geometryInfoOutParams outParams; + outParams.NdotVUnclamped = dot(normalW, viewDirectionW); + // The order 1886 page 3. + outParams.NdotV = absEps(outParams.NdotVUnclamped); + + #if defined(ENVIRONMENTBRDF) + // BRDF Lookup + outParams.environmentBrdf = getBRDFLookup(outParams.NdotV, roughness); + #else + outParams.environmentBrdf = vec3(0.0); + #endif + + outParams.horizonOcclusion = 1.0; + #if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + #ifdef HORIZONOCCLUSION + #ifdef GEOMETRY_NORMAL + #ifdef REFLECTIONMAP_3D + outParams.horizonOcclusion = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); + #endif + #endif + #endif + #endif + return outParams; +} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx new file mode 100644 index 00000000000..d27cbe233d8 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx @@ -0,0 +1,236 @@ +#ifdef REFLECTION + // _____________________________ Irradiance ________________________________ + // surfaceNormal is the direction to sample. Pass in a refracted vector to sample + // diffusely refracted light. + vec3 sampleIrradiance( + in vec3 surfaceNormal + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + , in vec3 vEnvironmentIrradiance + #endif + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + , in mat4 iblMatrix + #endif + #ifdef USEIRRADIANCEMAP + #ifdef REFLECTIONMAP_3D + , in samplerCube irradianceSampler + #else + , in sampler2D irradianceSampler + #endif + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + , in vec3 reflectionDominantDirection + #endif + #endif + #ifdef REALTIME_FILTERING + , in vec2 vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , in sampler2D icdfSampler + #endif + #endif + , in vec2 vReflectionInfos + , in vec3 viewDirectionW + , in float diffuseRoughness + , in vec3 surfaceAlbedo + ) { + vec3 environmentIrradiance = vec3(0., 0., 0.); + + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + vec3 irradianceVector = vec3(iblMatrix * vec4(surfaceNormal, 0)).xyz; + vec3 irradianceView = vec3(iblMatrix * vec4(viewDirectionW, 0)).xyz; + #if !defined(USE_IRRADIANCE_DOMINANT_DIRECTION) && !defined(REALTIME_FILTERING) + // Approximate diffuse roughness by bending the surface normal away from the view. + #if BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LAMBERT && BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LEGACY + { + float NdotV = max(dot(surfaceNormal, viewDirectionW), 0.0); + irradianceVector = mix(irradianceVector, irradianceView, (0.5 * (1.0 - NdotV)) * diffuseRoughness); + } + #endif + #endif + + #ifdef REFLECTIONMAP_OPPOSITEZ + irradianceVector.z *= -1.0; + #endif + + #ifdef INVERTCUBICMAP + irradianceVector.y *= -1.0; + #endif + #endif + #ifdef USESPHERICALFROMREFLECTIONMAP + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + environmentIrradiance = vEnvironmentIrradiance; + #else + #if defined(REALTIME_FILTERING) + environmentIrradiance = irradiance(reflectionSampler, irradianceVector, vReflectionFilteringInfo, diffuseRoughness, surfaceAlbedo, irradianceView + #ifdef IBL_CDF_FILTERING + , icdfSampler + #endif + ); + #else + environmentIrradiance = computeEnvironmentIrradiance(irradianceVector); + #endif + #endif + #elif defined(USEIRRADIANCEMAP) + #ifdef REFLECTIONMAP_3D + vec4 environmentIrradianceFromTexture = sampleReflection(irradianceSampler, irradianceVector); + #else + // TODO: What kind of irradiance map isn't 3D? + vec4 environmentIrradianceFromTexture = sampleReflection(irradianceSampler, reflectionCoords); + #endif + + environmentIrradiance = environmentIrradianceFromTexture.rgb; + #ifdef RGBDREFLECTION + environmentIrradiance.rgb = fromRGBD(environmentIrradianceFromTexture); + #endif + + #ifdef GAMMAREFLECTION + environmentIrradiance.rgb = toLinearSpace(environmentIrradiance.rgb); + #endif + // If we have a predominant light direction, use it to compute the diffuse roughness term.abort + // Otherwise, bend the irradiance vector to simulate retro-reflectivity of diffuse roughness. + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + vec3 Ls = normalize(reflectionDominantDirection); + float NoL = dot(irradianceVector, Ls); + float NoV = dot(irradianceVector, irradianceView); + + vec3 diffuseRoughnessTerm = vec3(1.0); + #if BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_EON + float LoV = dot (Ls, irradianceView); + float mag = length(reflectionDominantDirection) * 2.0; + vec3 clampedAlbedo = clamp(surfaceAlbedo, vec3(0.1), vec3(1.0)); + diffuseRoughnessTerm = diffuseBRDF_EON(clampedAlbedo, diffuseRoughness, NoL, NoV, LoV) * PI; + diffuseRoughnessTerm = diffuseRoughnessTerm / clampedAlbedo; + diffuseRoughnessTerm = mix(vec3(1.0), diffuseRoughnessTerm, sqrt(clamp(mag * NoV, 0.0, 1.0))); + #elif BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_BURLEY + vec3 H = (irradianceView + Ls)*0.5; + float VoH = dot(irradianceView, H); + diffuseRoughnessTerm = vec3(diffuseBRDF_Burley(NoL, NoV, VoH, diffuseRoughness) * PI); + #endif + environmentIrradiance = environmentIrradiance.rgb * diffuseRoughnessTerm; + #endif + #endif + + environmentIrradiance *= vReflectionInfos.x; + return environmentIrradiance; + } + + #define pbr_inline + #ifdef REFLECTIONMAP_3D + vec3 createReflectionCoords( + #else + vec2 createReflectionCoords( + #endif + in vec3 vPositionW + , in vec3 normalW + #ifdef ANISOTROPIC + , in anisotropicOutParams anisotropicOut + #endif + ) + { + #ifdef ANISOTROPIC + vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), anisotropicOut.anisotropicNormal); + #else + vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW); + #endif + + #ifdef REFLECTIONMAP_OPPOSITEZ + reflectionVector.z *= -1.0; + #endif + + // _____________________________ 2D vs 3D Maps ________________________________ + #ifdef REFLECTIONMAP_3D + vec3 reflectionCoords = reflectionVector; + #else + vec2 reflectionCoords = reflectionVector.xy; + #ifdef REFLECTIONMAP_PROJECTION + reflectionCoords /= reflectionVector.z; + #endif + reflectionCoords.y = 1.0 - reflectionCoords.y; + #endif + return reflectionCoords; + } + + #define pbr_inline + #define inline + vec3 sampleRadiance( + in float alphaG + , in vec3 vReflectionMicrosurfaceInfos + , in vec2 vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , in float NdotVUnclamped + #endif + #ifdef REFLECTIONMAP_3D + , in samplerCube reflectionSampler + , const vec3 reflectionCoords + #else + , in sampler2D reflectionSampler + , const vec2 reflectionCoords + #endif + #ifdef REALTIME_FILTERING + , in vec2 vReflectionFilteringInfo + #endif + ) + { + vec4 environmentRadiance = vec4(0., 0., 0., 0.); + // _____________________________ 2D vs 3D Maps ________________________________ + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + float reflectionLOD = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG, NdotVUnclamped); + #elif defined(LINEARSPECULARREFLECTION) + float reflectionLOD = getLinearLodFromRoughness(vReflectionMicrosurfaceInfos.x, roughness); + #else + float reflectionLOD = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG); + #endif + + // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection + reflectionLOD = reflectionLOD * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z; + + #ifdef LODINREFLECTIONALPHA + // Automatic LOD adjustment to ensure that the smoothness-based environment LOD selection + // is constrained to appropriate LOD levels in order to prevent aliasing. + // The environment map is first sampled without custom LOD selection to determine + // the hardware-selected LOD, and this is then used to constrain the final LOD selection + // so that excessive surface smoothness does not cause aliasing (e.g. on curved geometry + // where the normal is varying rapidly). + + // Note: Shader Model 4.1 or higher can provide this directly via CalculateLevelOfDetail(), and + // manual calculation via derivatives is also possible, but for simplicity we use the + // hardware LOD calculation with the alpha channel containing the LOD for each mipmap. + float automaticReflectionLOD = UNPACK_LOD(sampleReflection(reflectionSampler, reflectionCoords).a); + float requestedReflectionLOD = max(automaticReflectionLOD, reflectionLOD); + #else + float requestedReflectionLOD = reflectionLOD; + #endif + #ifdef REALTIME_FILTERING + environmentRadiance = vec4(radiance(alphaG, reflectionSampler, reflectionCoords, vReflectionFilteringInfo), 1.0); + #else + environmentRadiance = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD); + #endif + + #ifdef RGBDREFLECTION + environmentRadiance.rgb = fromRGBD(environmentRadiance); + #endif + + #ifdef GAMMAREFLECTION + environmentRadiance.rgb = toLinearSpace(environmentRadiance.rgb); + #endif + + // _____________________________ Levels _____________________________________ + environmentRadiance.rgb *= vReflectionInfos.x; + return environmentRadiance.rgb; + } + + #define pbr_inline + vec3 conductorIblFresnel(in conductorReflectanceOutParams reflectance, in float NdotV, in float roughness, in vec3 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. + return getF82Specular(NdotV, reflectance.F0, reflectance.F90, roughness); + + #else + return getReflectanceFromBRDFLookup(reflectance.F0, reflectance.F90, environmentBrdf); + #endif + } +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx index e9743f1c3a4..a3ff73a1fe9 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.fx @@ -2,6 +2,10 @@ #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) #endif +#if defined(GEOMETRY_COAT_NORMAL) + #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_SAMPLERNAME_,geometryCoatNormal) +#endif + #if defined(DETAIL) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx index d1fb7b6ef61..98d26854602 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.fx @@ -1,4 +1,4 @@ -#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) +#if defined(GEOMETRY_NORMAL) || defined(GEOMETRY_COAT_NORMAL) || defined(ANISOTROPIC) || defined(DETAIL) #if defined(TANGENT) && defined(NORMAL) varying mat3 vTBN; #endif diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 874c6c13e7e..1d338e65d02 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -60,11 +60,13 @@ precision highp float; #define CUSTOM_FRAGMENT_DEFINITIONS -#include -#include +#include +#include + #include #include -#include +#include +#include // _____________________________ MAIN FUNCTION ____________________________ void main(void) { @@ -80,52 +82,11 @@ void main(void) { #include - // _____________________________ Albedo & Opacity ______________________________ - albedoOpacityOutParams albedoOpacityOut; - -#ifdef BASE_COLOR - vec4 baseColorFromTexture = texture2D(baseColorSampler, vBaseColorUV + uvOffset); -#endif + // ______________________ Read Base properties & Opacity ______________________________ + #include -#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; + // _____________________________ Read Coat Layer properties ______________________ + #include #define CUSTOM_FRAGMENT_UPDATE_ALPHA @@ -133,31 +94,6 @@ void main(void) { #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) - -// Base roughness is modified by the coat layer -// rB′ = mix(rB, min(1, rB^4 + 2rC^4)^1/4 , C) where C = coat_weight (61) in OpenPBR spec - -// Sample specular lobe IBL and analytic lights separately from BRDF for each layer -// - pass in roughness, anisotropy, sample vector (and tangent?). Same code for reflection and refraction. -// - Coat: - one sample - pass in coat_roughness_anisotropy, coat_roughness, geometry_coat_normal -// - Base:- one sample - pass in geometry_normal, specular_roughness, specular_anisotropy -// - Translucent refraction -// - thin-walled refraction - i.e. no refraction -// Sample diffuse lobe IBL and analytic lights separately from BRDF for each layer -// - only Base layer has diffuse lobe -// - pass in base_diffuse_roughness, geometry_normal, base_color -// - Subsurface - refracted/transmitted diffuse - (geometry_thin_walled with subsurface is the same as glTF diffuse transmission) - - // _____________________________ AO _______________________________ ambientOcclusionOutParams aoOut; @@ -172,99 +108,23 @@ void main(void) { #endif ); -#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 + // _____________________________ Compute Geometry info for coat layer _________________________ + geometryInfoOutParams coatGeoInfo = geometryInfo( + normalW, viewDirectionW.xyz, coat_roughness, geometricNormalW ); - float roughness = reflectivityOut.roughness; - float diffuseRoughness = reflectivityOut.diffuseRoughness; - - #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) - aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; - #endif - - // _____________________________ Compute Geometry info _________________________________ - #include + // _____________________________ Compute Geometry info for base layer _________________________ + // Adjust the base roughness to account for the coat layer. Equation 61 in OpenPBR spec. + specular_roughness = mix(specular_roughness, pow(min(1.0, pow(specular_roughness, 4.0) + 2.0 * pow(coat_roughness, 4.0)), 0.25), coat_weight); + geometryInfoOutParams baseGeoInfo = geometryInfo( + normalW, viewDirectionW.xyz, specular_roughness, geometricNormalW + ); -// Share code for reflection and refraction -// Pass in values to select between reflection and refraction, diffuse and specular, anisotropic and isotropic - // _____________________________ Reflection Info _______________________________________ + // _____________________________ Base Diffuse Layer IBL _______________________________________ #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 - , reflectionSampler + // Pass in a vector to sample teh irradiance with (to handle reflection or ) + vec3 baseDiffuseEnvironmentLight = sampleIrradiance( + normalW #if defined(NORMAL) && defined(USESPHERICALINVERTEX) , vEnvironmentIrradiance #endif @@ -277,56 +137,180 @@ vec4 specularColor = vSpecularColor; , vReflectionDominantDirection #endif #endif - #ifndef LODBASEDMICROSFURACE - , reflectionSamplerLow - , reflectionSamplerHigh - #endif #ifdef REALTIME_FILTERING , vReflectionFilteringInfo #ifdef IBL_CDF_FILTERING , icdfSampler #endif #endif - , viewDirectionW - , diffuseRoughness - , surfaceAlbedo - ); + , vReflectionInfos + , viewDirectionW + , base_diffuse_roughness + , base_color + ); + + // _____________________________ Base Specular Layer IBL _______________________________________ + + #ifdef REFLECTIONMAP_3D + vec3 reflectionCoords = vec3(0., 0., 0.); #else - #define CUSTOM_REFLECTION + vec2 reflectionCoords = vec2(0., 0.); #endif + reflectionCoords = createReflectionCoords(vPositionW, normalW); + float specularAlphaG = specular_roughness * specular_roughness; + vec3 baseSpecularEnvironmentLight = sampleRadiance(specularAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , baseGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + ); + + baseSpecularEnvironmentLight = mix(baseSpecularEnvironmentLight.rgb, baseDiffuseEnvironmentLight, specularAlphaG); + + vec3 coatEnvironmentLight = vec3(0., 0., 0.); + if (coat_weight > 0.0) { + #ifdef REFLECTIONMAP_3D + vec3 reflectionCoords = vec3(0., 0., 0.); + #else + vec2 reflectionCoords = vec2(0., 0.); + #endif + reflectionCoords = createReflectionCoords(vPositionW, normalW); + float coatAlphaG = coat_roughness * coat_roughness; + coatEnvironmentLight = sampleRadiance(coatAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , coatGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + ); + } + + #endif - // _________________________ Specular Environment Reflectance __________________________ - float reflectanceF0 = reflectivityOut.reflectanceF0; - vec3 specularEnvironmentR0 = reflectivityOut.colorReflectanceF0; - vec3 specularEnvironmentR90 = reflectivityOut.colorReflectanceF90; - #include + // _______________________ F0 and F90 Reflectance _______________________________ + + // Coat + dielectricReflectanceOutParams coatReflectance; + coatReflectance = dielectricReflectance( + coat_ior // inside IOR + , 1.0 // outside IOR is air + , vec3(1.0) + , coat_weight + ); + + // Base Dielectric + dielectricReflectanceOutParams baseDielectricReflectance; + { + float effectiveCoatIor = mix(1.0, coat_ior, coat_weight); + baseDielectricReflectance = dielectricReflectance( + specular_ior // inside IOR + , effectiveCoatIor // outside IOR is coat + , specular_color + , specular_weight + ); + } + + // Base Metallic + conductorReflectanceOutParams baseConductorReflectance; + baseConductorReflectance = conductorReflectance(base_color, specular_color, specular_weight); + // ______________________________ IBL Fresnel Reflectance ____________________________ + #ifdef REFLECTION + + // Dielectric IBL Fresnel + // The colored fresnel represents the % of light reflected by the base specular lobe + // The non-colored fresnel represents the % of light that doesn't penetrate through + // the base specular lobe. i.e. the specular lobe isn't energy conserving for coloured specular. + float dielectricIblFresnel = getReflectanceFromBRDFLookup(vec3(baseDielectricReflectance.F0), vec3(baseDielectricReflectance.F90), baseGeoInfo.environmentBrdf).r; + vec3 dielectricIblColoredFresnel = getReflectanceFromBRDFLookup(baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, baseGeoInfo.environmentBrdf); + + // Conductor IBL Fresnel + vec3 conductorIblFresnel = conductorIblFresnel(baseConductorReflectance, baseGeoInfo.NdotV, specular_roughness, baseGeoInfo.environmentBrdf); + + // Coat IBL Fresnel + float coatIblFresnel = 0.0; + if (coat_weight > 0.0) { + coatIblFresnel = getReflectanceFromBRDFLookup(vec3(coatReflectance.F0), vec3(coatReflectance.F90), coatGeoInfo.environmentBrdf).r; + // Prevent the light reflected by the coat from being added to the base layer + dielectricIblFresnel -= coatIblFresnel; + dielectricIblColoredFresnel = max(dielectricIblColoredFresnel - vec3(coatIblFresnel), 0.0); + conductorIblFresnel = max(conductorIblFresnel - vec3(coatIblFresnel), 0.0); + } + #endif + + // _____________________________ Base Layer IBL ______________________________________ + vec3 slab_diffuse = vec3(0., 0., 0.); + vec3 slab_glossy = vec3(0., 0., 0.); + #ifdef REFLECTION + slab_diffuse = baseDiffuseEnvironmentLight * vLightingIntensity.z; + + // Account for energy loss due to specular reflectance + vec3 baseSpecularEnergy = vec3(dielectricIblFresnel + coatIblFresnel); + slab_diffuse *= clamp(vec3(1.0) - baseSpecularEnergy, 0.0, 1.0); + slab_diffuse *= base_color.rgb; + slab_diffuse *= aoOut.ambientOcclusionColor; + + // Add the specular environment light + slab_glossy = baseSpecularEnvironmentLight * dielectricIblColoredFresnel * vLightingIntensity.z; + #endif + + // _____________________________ Metal Layer IBL ____________________________ + vec3 slab_metal_IBL = vec3(0., 0., 0.); + #ifdef REFLECTION + slab_metal_IBL = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; + #endif + + // _____________________________ Coat Layer IBL ____________________________ + vec3 slab_coated_base = vec3(0., 0., 0.); + #ifdef REFLECTION + if (coat_weight > 0.0) { + slab_coated_base = coatEnvironmentLight * coatIblFresnel * vLightingIntensity.z; + } + #endif + // _____________________________ 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; + vec3 baseDiffuseDirectLight = vec3(0., 0., 0.); + #ifdef SPECULARTERM + vec3 baseSpecularDirectLight = vec3(0., 0., 0.); + #endif + + // Direct Lighting Variables + #if defined(SPECULARTERM) && defined(LIGHT0) + vec3 coloredFresnel; + #endif + float aggShadow = 0.; + float numLights = 0.; + #include[0..maxSimultaneousLights] + #include[0..maxSimultaneousLights] + #include[0..maxSimultaneousLights] + #include[0..maxSimultaneousLights] + + aggShadow = aggShadow / numLights; + + + + // Handle direct lighting + vec3 finalDiffuseDirect = baseDiffuseDirectLight * vLightingIntensity.x; + finalDiffuseDirect *= base_color.rgb; + + + // ___________________ Specular Layer Direct Lighting ___________________________ + vec3 finalSpecularDirect = vec3(0., 0., 0.); + #ifdef SPECULARTERM + baseSpecularDirectLight = max(baseSpecularDirectLight, 0.0) * vLightingIntensity.x * vLightingIntensity.w; + finalSpecularDirect += baseSpecularDirectLight; + #endif + + // _____________________________ Emissive ________________________________________ vec3 finalEmission = vEmissionColor; #ifdef EMISSION @@ -340,14 +324,39 @@ vec4 specularColor = vSpecularColor; #endif finalEmission *= vLightingIntensity.y; - // ______________________________ Ambient ________________________________________ - #ifdef AMBIENT_OCCLUSION - finalDiffuse *= mix(vec3(1.), aoOut.ambientOcclusionColor, 1.0 - vAmbientOcclusionInfos.y); - #endif - + // _____________________________ Final Color Composition ________________________ #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - #include + // TEMP + vec3 slab_subsurface = vec3(0., 0., 0.); + vec3 slab_translucent_base = vec3(0., 0., 0.); + vec3 slab_fuzz = vec3(0., 0., 0.); + float subsurface_weight = 0.0; + float transmission_weight = 0.0; + float fuzz_weight = 0.0; + + vec3 material_glossy_diffuse = slab_diffuse + slab_glossy; + vec3 material_opaque_base = mix(material_glossy_diffuse, slab_subsurface, subsurface_weight); + vec3 material_dielectric_base = mix(material_opaque_base, slab_translucent_base, transmission_weight); + vec3 material_base_substrate = mix(material_dielectric_base, slab_metal_IBL, base_metalness); + vec3 material_coated_base = material_base_substrate + slab_coated_base; + vec3 material_surface = mix(material_coated_base, slab_fuzz, fuzz_weight); + vec4 material_final = vec4(material_surface, alpha); + + vec4 finalColor = vec4( + material_final.rgb + + finalDiffuseDirect + + finalSpecularDirect + + finalEmission + , alpha); + + // _____________________________ EmissiveLight _____________________________________ + finalColor.rgb += finalEmission; + + #define CUSTOM_FRAGMENT_BEFORE_FOG + + // _____________________________ Finally ___________________________________________ + finalColor = max(finalColor, 0.0); #include #include(color, finalColor) diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index fb6e3f845d4..f04693f9aac 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -39,6 +39,9 @@ attribute vec4 color; #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight) +#include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) +#include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) @@ -217,6 +220,9 @@ void main(void) { #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_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_MATRIXNAME_,coatWeight,_INFONAME_,CoatWeightInfos.x) + #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) + #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index c2a119bfa7e..b0e32a9abac 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -41,6 +41,10 @@ uniform vBaseColor: vec4f; uniform vBaseDiffuseRoughness: f32; uniform vReflectanceInfo: vec4f; uniform vSpecularColor: vec4f; +uniform vCoatWeight: f32; +uniform vCoatColor: vec3f; +uniform vCoatRoughness: f32; +uniform vCoatIor: f32; uniform vEmissionColor: vec3f; uniform vBaseWeightInfos: vec2f; @@ -55,6 +59,12 @@ uniform vSpecularColorInfos: vec2f; uniform specularColorMatrix: mat4x4f; uniform vBaseMetalRoughInfos: vec2f; uniform baseMetalRoughMatrix: mat4x4f; +uniform vCoatWeightInfos: vec2f; +uniform coatWeightMatrix: mat4x4f; +uniform vCoatColorInfos: vec2f; +uniform coatColorMatrix: mat4x4f; +uniform vCoatRoughnessInfos: vec2f; +uniform coatRoughnessMatrix: mat4x4f; uniform vGeometryNormalInfos: vec2f; uniform geometryNormalMatrix: mat4x4f; uniform vGeometryOpacityInfos: vec2f; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx deleted file mode 100644 index 1f45834e4b8..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalColorComposition.fx +++ /dev/null @@ -1,33 +0,0 @@ -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 index e3fc7254aa1..ee6e9c4b435 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx @@ -51,23 +51,4 @@ aggShadow = aggShadow / numLights; 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 +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 947651182d4..5bdeb89db97 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -4,7 +4,11 @@ #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_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_SAMPLERNAME_,coatWeight) +#include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) +#include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) +#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx new file mode 100644 index 00000000000..e4d3dceeea3 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx @@ -0,0 +1,176 @@ +#ifdef REFLECTION + struct reflectionOutParams + { + environmentRadiance: vec4f + , environmentIrradiance: vec3f + #ifdef REFLECTIONMAP_3D + , reflectionCoords: vec3f + #else + , reflectionCoords: vec2f + #endif + #ifdef SS_TRANSLUCENCY + #ifdef USESPHERICALFROMREFLECTIONMAP + #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) + , irradianceVector: vec3f + #endif + #endif + #endif + }; + + #define pbr_inline + #ifdef REFLECTIONMAP_3D + fn createReflectionCoords( + vPositionW: vec3f, + normalW: vec3f, + #ifdef ANISOTROPIC + anisotropicOut: anisotropicOutParams, + #endif + ) -> vec3f + { + var reflectionCoords: vec3f; + #else + fn createReflectionCoords( + vPositionW: vec3f, + normalW: vec3f, + #ifdef ANISOTROPIC + anisotropicOut: anisotropicOutParams, + #endif + ) -> vec2f + { + var reflectionCoords: vec2f; + #endif + #ifdef ANISOTROPIC + var reflectionVector: vec3f = computeReflectionCoords( vec4f(vPositionW, 1.0), anisotropicOut.anisotropicNormal); + #else + var reflectionVector: vec3f = computeReflectionCoords( vec4f(vPositionW, 1.0), normalW); + #endif + + #ifdef REFLECTIONMAP_OPPOSITEZ + reflectionVector.z *= -1.0; + #endif + + // _____________________________ 2D vs 3D Maps ________________________________ + #ifdef REFLECTIONMAP_3D + reflectionCoords = reflectionVector; + #else + reflectionCoords = reflectionVector.xy; + #ifdef REFLECTIONMAP_PROJECTION + reflectionCoords /= reflectionVector.z; + #endif + reflectionCoords.y = 1.0 - reflectionCoords.y; + #endif + + return reflectionCoords; + } + + #define pbr_inline + fn sampleReflectionTexture( + alphaG: f32 + , vReflectionMicrosurfaceInfos: vec3f + , vReflectionInfos: vec2f + , vReflectionColor: vec3f + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , NdotVUnclamped: f32 + #endif + #ifdef LINEARSPECULARREFLECTION + , roughness: f32 + #endif + #ifdef REFLECTIONMAP_3D + , reflectionSampler: texture_cube + , reflectionSamplerSampler: sampler + , reflectionCoords: vec3f + #else + , reflectionSampler: texture_2d + , reflectionSamplerSampler: sampler + , reflectionCoords: vec2f + #endif + #ifndef LODBASEDMICROSFURACE + #ifdef REFLECTIONMAP_3D + , reflectionLowSampler: texture_cube + , reflectionLowSamplerSampler: sampler + , reflectionHighSampler: texture_cube + , reflectionHighSamplerSampler: sampler + #else + , reflectionLowSampler: texture_2d + , reflectionLowSamplerSampler: sampler + , reflectionHighSampler: texture_2d + , reflectionHighSamplerSampler: sampler + #endif + #endif + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo: vec2f + #endif + ) -> vec4f + { + var environmentRadiance: vec4f; + // _____________________________ 2D vs 3D Maps ________________________________ + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + var reflectionLOD: f32 = getLodFromAlphaGNdotV(vReflectionMicrosurfaceInfos.x, alphaG, NdotVUnclamped); + #elif defined(LINEARSPECULARREFLECTION) + var reflectionLOD: f32 = getLinearLodFromRoughness(vReflectionMicrosurfaceInfos.x, roughness); + #else + var reflectionLOD: f32 = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG); + #endif + + #ifdef LODBASEDMICROSFURACE + // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection + reflectionLOD = reflectionLOD * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z; + + #ifdef LODINREFLECTIONALPHA + // Automatic LOD adjustment to ensure that the smoothness-based environment LOD selection + // is constrained to appropriate LOD levels in order to prevent aliasing. + // The environment map is first sampled without custom LOD selection to determine + // the hardware-selected LOD, and this is then used to constrain the final LOD selection + // so that excessive surface smoothness does not cause aliasing (e.g. on curved geometry + // where the normal is varying rapidly). + + // Note: Shader Model 4.1 or higher can provide this directly via CalculateLevelOfDetail(), and + // manual calculation via derivatives is also possible, but for simplicity we use the + // hardware LOD calculation with the alpha channel containing the LOD for each mipmap. + var automaticReflectionLOD: f32 = UNPACK_LOD(textureSample(reflectionSampler, reflectionSamplerSampler, reflectionCoords).a); + var requestedReflectionLOD: f32 = max(automaticReflectionLOD, reflectionLOD); + #else + var requestedReflectionLOD: f32 = reflectionLOD; + #endif + #ifdef REALTIME_FILTERING + environmentRadiance = vec4f(radiance(alphaG, reflectionSampler, reflectionSamplerSampler, reflectionCoords, vReflectionFilteringInfo), 1.0); + #else + environmentRadiance = textureSampleLevel(reflectionSampler, reflectionSamplerSampler, reflectionCoords, reflectionLOD); + #endif + #else + var lodReflectionNormalized: f32 = saturate(reflectionLOD / log2(vReflectionMicrosurfaceInfos.x)); + var lodReflectionNormalizedDoubled: f32 = lodReflectionNormalized * 2.0; + + var environmentMid: vec4f = textureSample(reflectionSampler, reflectionSamplerSampler, reflectionCoords); + if (lodReflectionNormalizedDoubled < 1.0){ + environmentRadiance = mix( + textureSample(reflectionHighSampler, reflectionHighSamplerSampler, reflectionCoords), + environmentMid, + lodReflectionNormalizedDoubled + ); + } else { + environmentRadiance = mix( + environmentMid, + textureSample(reflectionLowSampler, reflectionLowSamplerSampler, reflectionCoords), + lodReflectionNormalizedDoubled - 1.0 + ); + } + #endif + + var envRadiance = environmentRadiance.rgb; + + #ifdef RGBDREFLECTION + envRadiance = fromRGBD(environmentRadiance); + #endif + + #ifdef GAMMAREFLECTION + envRadiance = toLinearSpaceVec3(environmentRadiance.rgb); + #endif + + // _____________________________ Levels _____________________________________ + envRadiance *= vReflectionInfos.x; + envRadiance *= vReflectionColor.rgb; + + return vec4f(envRadiance, environmentRadiance.a); + } +#endif diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 35c5c6c3a7c..2bc850fab5f 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -48,7 +48,7 @@ #include #include #include -#include +#include // _____________________________ MAIN FUNCTION ____________________________ @fragment @@ -90,7 +90,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs { , baseColorFromTexture , uniforms.vBaseColorInfos #endif - , uniforms.baseWeight + , uniforms.vBaseWeight #ifdef BASE_WEIGHT , baseWeightFromTexture , uniforms.vBaseWeightInfos diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index a7ad5006f1e..03832c9da64 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -35,6 +35,9 @@ attribute color: vec4f; #include(_DEFINENAME_,METALLIC_ROUGHNESS,_VARYINGNAME_,BaseMetalRough) #include(_DEFINENAME_,SPECULAR_WEIGHT,_VARYINGNAME_,SpecularWeight) #include(_DEFINENAME_,SPECULAR_COLOR,_VARYINGNAME_,SpecularColor) +#include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight) +#include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) +#include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) @@ -205,6 +208,9 @@ fn main(input : VertexInputs) -> FragmentInputs { #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_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_MATRIXNAME_,coatWeight,_INFONAME_,CoatWeightInfos.x) + #include(_DEFINENAME_,COAT_COLOR,_VARYNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) + #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) 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 661efd4329e..b17bda7ab07 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 @@ -162,14 +162,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component )} - + {material instanceof PBRMaterial && ( + + )} {material instanceof PBRMaterial && ( <> { if (useOpenPBR) { - // eslint-disable-next-line github/no-then + const material = babylonMaterial as OpenPBRMaterial; + material.coatWeight = coatWeight; + material.coatWeightTexture = coatWeightTexture; + material.coatRoughness = coatRoughness; + material.coatRoughnessTexture = coatRoughnessTexture; + // material.coatNormalTexture = coatNormalTexture; + // material.coatNormalTextureScale = coatNormalTextureScale; return; } const material = babylonMaterial as PBRMaterial; diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Metal-vs-Weight.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Metal-vs-Weight.png new file mode 100644 index 0000000000000000000000000000000000000000..f69a2107bd766b05b6deb99bde0294a168f7dcf4 GIT binary patch literal 141630 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 literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Roughness-vs-Weight.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-F82-Specular-Roughness-vs-Weight.png new file mode 100644 index 0000000000000000000000000000000000000000..8b122826c50576558057e3f46cc289c0f1a0d84d GIT binary patch literal 111428 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


f2j8#8m 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 SJ9YrjPGEGQpVOS!m$dEb8 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ξosyU;u$31EA^yi23|Y7PtkL93tzb zuz%-CkK?)vOZ+cF3=W2E^>6ekQyNKnDs6@ye|?Sf2IFGd?UI4+M@vOs=u{e7P$k=P zh%0Y@#_`s?0DG)UCyO|KIuClylEH5bqhClEd?XR4N<`nB4A%cWP*P-h%X1!i#*eb9ce|`|MN%IzpSC`DrrhLbm5Pf_sN!V= z634jM5wV0TAi?37Wkv! z=kEfQrwcPt9tiA!m%%nCW6$K0Rlnl5T>U%Sz<623Ti>z=BdJ#q*4#m&9-wV}3f4|= zX35;+P|8h3-~D;}#jpuB=`NO!>fp)NFsb|FAZuBr4O=Uf2OZ&8lwo#-XN4VgtPqDo z#ms!a4P^;iFkGZ)_N>Ei<2}8Ss)+YF#s13vzvodPd6=imPIZ680%Rnq4NWUQ23mx> z82l`rK@ClFQuKZOC)BE7?{fi5%Y58)D`8Ze8mqPUTFx9Ua~NKsoVc0+_>Eeo8Gb_1 z!X;d&1Q{TMI(C!Ur+3}tRKazuVm#PQJB;G<`2Q~FmL)PF4L9@6&r<$Oeh?-4moPgPf21lzkZ4^WBHQJK@`l4RE@z_4YU1dMjx^v{Gxf}s z(<;^L(nMOBeeuw_YS4s!c+lecI49t-ssO?1v7GPUxjw=tWRGs`(?h0_?@$fbj>@>g zl%3d4Npy*13@lo0G|y3hCI=f>sA_X96DGTid|}*uu3)f~i2R6#jt2lFPp}pg@nq8c zU{t4Tb)IrIwIq-GuBkkywO{&;TMQRAnSY2Qq9M@0AyR+))&4a{Wn55CUJBrK0;xA0 z9#-ae)C*)DWMdDsEBz}?gq-u(K^X7>VRhSBj>Igw=adTk#lhL&@BaXZKzF|#U{2>m z32f(tSp#X+)aJn@a`oXK%wh5 zT)t9^B+HVbC=;1%_9w(jYgp=aR7QX(2vLerF)5#WWHcHY2!HzNAMD$^^7X&?f3Cdh z>YH!9%a97fO=E0?GV68#fR$2t*@#4xWwX4{ z6&-1ONFq-1(crnq`u!0R5Xt`f*#id-JooHVSthT4<6Du*bynH8Kp-$+wsY!R`lgg) zB3A|w5tB^>#K>%N0h;N^SR2et6!NAc8U2tQbA$+tuM;u~U;$+QheW^f2fy*y_rE8Y zI+HVL0^?D!ci+P6mwS~+h+t{H2LR)$$poxT>RvaS>t-^Of&ny7@=<>@ET4TWFB&04 zk|bx3KK{BJ-*o=W@oTPqL$tQs)tmx37r1|~~@1;a445D}0g`N&vE zY!Zf2HfbV4N>OrjBa?2$MH{W6m!`Xl_431&~kTnc% z5*9Yt)qHa7i7&am9&9FLL?pq8#x!v|O zBDJ`XNjaw*H7qIt$Xaod3~MDMuWjV+7h#H@hYuXsf8}+{`!0L>$;aOG);s-FIFreXwnrG48LtHQ z)WCp57!a>X3MRzaNNBX-@@7jLz=2K*bg>_pWE89gOJqXUXy#>DL(xy05mVirOSRIF zrB$t#7P@t#>ZY0Nb(*?4xPPT+>fyMW%aXco6fps09XT3T06>}nn40k;-}9 zyJF9tl>^r_O3O4meEp4nJG^BWE)ba|0B0CvPoQy$&jztz7&g{{%ZY->5rQnp%+El3 z{?fOE9C6QpECg#b+19FpxEv+*mc&M;_UfRjsP^tz%!{HZo4NTOaNQ`KO3up~&Ax_6 zGy#!5pO?&_6m>eXBk8H{eO;-l-!J~=FaFi*4qUac@8H7nUe#3l4_x7oRbpZx+yGIi zQv5`aCyg)aCMMcjEg8auth#pe5$l5%8-amG$Yfl@RD`4&WG$(dG|I8gvc%qGrW7YK zO$38v;snLMJ^4dUe59|ibnbDqohk~^64j?^C zgs)K{Rp(oo!1b+Rnk9^~%!{RY7}t7XalVtt^{oK_$gI=ToMuT~RuwWa_qQf!`qjXB z-VjhK(@9+e)OA&tS}B07&7yz)WL?+8qPp>xTS;Vl_8%~#T<(0eR>HD%A(P!O1W@Ge zgbIP2-OX$+NdN`f%l8It@CRmAnxyc|ECQN~cFATJ?d+ShE(VFfx>0E+wbGOE`0)Pa zbE9Iumn|B6AgYG;Ec6tD);t*IN-JPUQqk19B2|}lS=NY3Wt+_%t~Xc9uq&-Kb$ zrCEwB5umOJ5rh;XMOCS_^${}*A&7_w2a_B~XyU4(^P_&Q8>M-3Grw@^xkfb_#nrFB zaa>e~UUxmYXL954VB?*?QCTS|B{K_TMQ)nN@nql>VX;Esg(JftXBMX0=9bog!CD0o zl4-bUlL(P?zIJ>u6M{g>gftFoTFh{3I7t)P>vfw(O97B%olc75NtPu|-Bdu6ysq+^ zfJswtKFcRfuh-M6nM|szBa#HS`Wx$`jjALmMNi5>QN7`fw=G_F@YK;Kue$yg^G0bq zB)QEnh)63TrJVuwJ_13B#Ds1_#w{vc+((ELVOj_XAc9Glw5m00g{1pupSpadr)mP= zs?f)a(c$H}NhOn1F3fckAqL}dqc}-Ysi@PH0+<9gN{z-vqZ%eav&AQYkjCQ*1!|WFZA-f0ELxqvQ%`t2?|sUMOp3JH@`j_?3tV2 zw;;|Qe>!D4eT0j;n(HJi0)PNknt)j*i4?+~#SMbERXw2ArazRIqb1@zFIWpek#^*yYL@3Z z!@Oz~ZHm;d20HD*!(llAy8k^hH0Wp;l0G5{*^1J}TMypPm zbbFmf)n%6N$_l{b8EOZYOOT z-OD5~bh4yrbgz?jyQCE_E~br!vMJ`0&f-!!s*1TRt;YS;Vk}8N_KiQ!t9p5%3o>0k zc>UIea|f@v)?_Ya`ko9#8Xy;ljV7N0O;%5ZjSz}V7u6bu8AD118ZDXc5ddWFD$UZw z&iGn?Vn;a(e%^Tc+LB$A2qi+lzuKK&01(8gDjEfHYf>yO^nj_8ik0OBMS9=fg`%uS zMYFijyKH3vMUw7aDvGk`G^rGG-G$M(o|H8TY-+BXN-kmDXg!>CI$1;YxW-Nj7wGVF!w%fzCa%- zhkBbYOKa8|t7?p@-{sGQ;Pumw&|%zPZPLdy~RM&AIPv?yp`mVbX=Kz7JEax1%A3urTjj`T-Wq(JAb9Vqi z)C;B%paBrS#nWCi1J!}ZBV;d(zDmjcy@C~tLLi!iB~X^SB^77`j3t#R$AP5Ff%^jg5g>?mlWAUNyxf|%m$SVN%5CXYvP0gVpwx;BOT53v6uq|7k z^UKAp3wfm7d6Q)BjZ)=pY8ZndaF zik4C!vFnhwA|%x2H}~JYhpMl>^Yw0+H0>yK?jD$|RYm&$%t}6&sCb7u`Wywxcv%iW zduK7>4g^2|)d2w}G2J#tEUF<5-i;SgqtEd##u%>; zJqxMpxbNok<^a2K*o~ctFi{XJt#&a47Bf7aS8cHCFk#J(q+0=$ zN{qFZ=cTr0B9hI8pbNNc-qhTzPf{zHS*?XF^j*Jt%MIJQ1m?!g7)z_`R!i}Iq_FcEE znc1t_R;wGB7bdnqfIjs>%}cJr`23WaFmf;`xgrTS%X)TCq-42h*3wjSwqb}-WLclK z;~Q5GUCifCcPVYTL3eH1ICc(D-%a`c0@MaCAL$*X+5i-h5zLeb-8~Y3Tj*p{eO_BJ z5(z12Ly~v0q5voo>Ut)?m{>xHAv`}F$0Rp>nzsz@r@0u|Qko!g->vI1q@iqCl9W>C zjIC9XP+jM>jANM3wKglcja@wFmbYe;qWRFprevlM52xMOH7ZIjMo*`Wh+;$o+|EyM zepEB&2;Mr8$ed}w*jvdU@d8GEcc+1OqDpU<0dEO44nlM}^GsmwWXc50Y~au5S{x^g zNg5NuJIQr)WTuZl{-!rKP$OcZ`LwXNA%Ida)#u~fz#V}cOEEQ7r!{9{-paOB1pp#m zvo>);OhHP`r!_MYFq}@gW}9{?Ca;Bwuv)gojD1rA77$I$b>1TWz9%$hX~(0&R5fTUbc=%mDi=X!_8sny6&{)F;FniP1PI; zYO$?UCQt)O5(vA)Ft4T6Ruy6l2)=AZI0#ACBL!en!Y*&6RYUStLBt>DQi~x%t#+B_ zkEwHC+(?^=(6SYGFvZwU%jq~w2e-l;0U*~Bf)L>O^e_#FM&RJNHFOll6!^1;b?DMs zOoZL4L8uO{Z4d^#II966efLkl5hXl5&p9_1(5Bxz9jDkYTkVObu|J-c=hHR}sSDk* zo=XNctL7pcQ`)votC!*nY+dU5j$`cJ+&|y#(pq5{qNOZC2(=?EQeX zsFD%Ved`wTM+)-lli~>^}qG6{~JGB9iN_;=kvOi)g3=MpJPY_M5N3@ zh^MVyA4YABlDv6*zV0KqL?(&D>AY-PO9^Ug7dq)~Na1Q+*8}iabd3Cbe7gt-! zua=DfdPH-chVC>!r7oD8qE>>E+nNoAU8H(eoiApFRiQPgC69-@`S>{O zuF;M0Elw2BBh%^pDE&^&iSbx!5MspU@O)Gj*%YqFu9*dZ*0iuiyDZd!iA(Vh?yh2M z%ebfp%MRRRr3V=k^_i3WPOpGK@{NnY#lL z#T38xwZHu8J716H`!0QU4@OuE#Hrh|-5=)<0uM1PYi<=DmigwYTefN`Xwg=i*M^_V zgeg`nOj2w9@a194MZ z&FZ`scPOP1ypoF-c9lDdfKXk z>6~ld#S5GPoXpjlR&2!7ni6AVi6N*}RSrUVD?=Y@tARlcYSA&q=Ae0LsQeftxx2#3-AoDZF{SAI3=x z0FVGw?P)F!*aH@Yb1q#c+qTKH6LdEtfDmJh@p_krF}7#j59#Aq4{k6{Y3v6AT54Xl zay@pi8;{51^SJ={)N^SreNy+f{Ow%m{bOqj9NI*wt> zIS3&kD5OBl-TA!K+Ahp005mfR1WxN(`w$Uq&bd~*uqRVwYp)5NDW2wyi6xM#5fQj+ zb9X!J_RU-nV`OW#x<8zA3_+2CnYNO*HS7+8u4Y6yPP;F95IP@{9VJ&6`A}qvf zwo;YIn?Vu^EZ~r0K;XQ!X&k`NnyGq>)QVb#ZE4`{>O<}uTo4gZ9Qf7K@%8`4jvV=}T z3iDbVU_W$oZ7r{a_Po?j=Cze_bG6&bHVBrbv_^=~%-!uguVzk!NZM)>!67AbZ;G`# zGS^lJc`dD~I=C7{d~3bhg#gIQocFuIt0O?GmJ*qoD{QL<=5@_oj9T>edaTWM(=f!; zhoH^0*}CMWN{D&0<1v>~OSRI#CA@ifT5C47z_{jWZ`HUhFqql8E$A0XGEjFx3^4-0 z!{ZwQ41Id@G^ZGMT~zbBu8*fRrEW$iqOR{9@pejVby=$e9p^kR+01IS)~xGAkQ}TQ zJB(e)zGgem+eJv{`CPVbQ*$s3f&`94=oUF@Ggqv&YIOv3GbXIr@~U}jjO2)Av%|i3 z!0YP?of5ODGRnGb!WaT;LsKicnz1CF{1XA<#60ycsyOayd|H&ZliVZ%Z?6O_AWd7ImxUogjj%zI9_Z zfIvV<`@6d@x@Q06;!D&Bf8*ExraC#o<7v6R+W++J_0znb&MTw;)XlW2A=5bZ%4nuZ zyd&Tk>79q2J3Kuv&!S@H3CyYudN-ICD*3r zOt7u`PKyn1_9Fo`wfFC?B9dj@r_?8TnwL^Q)rm;eO4X^0QGy%Xrg%J_)peY@82NZ! zW5lOrC4xS^8~a|22H)yRI1pd(I7sxjf8&4b#)(X-*|OyiUf%rl2iMFP(3|##RTUvKKc3c~djF}?E@i0H(v;AqE`mWWep)Ld=G=0-Fh9gi zn_;U3Oda&Nt{li4AmX+eIGXy9!eQ!?a4GffdWyu}bl)X+o%1RjQeXU4n zk@>o8!Z_}_oC|?1rLLtRxG)l4P6YrsN^o}tYUackV*-G~)nOWwle1u-($&6iRo@&J z=Fl;{=*Nd`y?=aG@Wl-ffL*}Gu}_hk8ZvU=c`jQiW*&ueZ2)cT!oE+ZbFMCZ47E8C zrI^gH2#1zAacZW#i%@Wb|uFnd!St-f{Rc*_a z+`(~O+O}!lYEvU7Q>&!_z-i46o&rV&fVTp?BoW*dsJaVLKa79-Z~YI89*17mS|x?u zH1vJa2B)meaNmayulBExr)A5?K?$Aw)#ItHDKTGOG6eHVr(2=M;xz7NUW`WW1FEd>!p z$kd-t+x6H5B1Au*a?M^!ozFvFWZeJ&AOJ~3K~!5U`pK&YM_6;qP5VFu7tRS>QgNZL z6mvxUjsNC1zUZ3$lMDXv!(aHKe}|u3RCt&Ol|{{(!C}99JkBgh)#h9%($mvw02Jjs zm&d2&BB?9Pr8Z^~A#m(dYE@g)E(QQJa1mK^y*Z4v)_ou5wXWMnEMuRZ=PW`*GIpt4 z8X=>qUo^K4V|QG(5P1l4UTdjJ?58bnMZst*4cS`p7>Eh?yO9uHTutZN1c@2vxd`(z zZ$pnm7n`~}h!7z$Qx`%508@#bh{Tvk!u8?s$q(QB!SDamimz`|oSQjdYwqC3Ihz|I zf$0!wQ{8d_5kz|Za2obqEfo-1_#&CCW-MHrxjG^qrlBSGY$QY^)gYuR!Q!nrCTrYLHjSfWT(J#RHiIJbOUHdQwRVP4nTn)ZFD zs)6~v>!~!Irm^If`lM#-l2f7(q61X5x0VM?eGmm;B92j5x)4(8Ztq_F*`NIIU;gD^ zeD%YBmH^(ImNCYnZQk-Q?Y5lzAR(k+ZE*{dE=CyVwN`CRe4!>FQH*TOMVOF-P^&to zw3XU*i5Oe+u@3-n7~`9#Wr*x3B9hzXib7N0ty?ZlS+F&`2!Bmotm+*2Fm$K2w$h5# zrIgy-omzDk+g3vabGteWeUP7ean;PgQIfoV_1v0Hqof#!E`r`jL_in52ZflJLl6nV zp&vi|;4A;^kG>P)8qwJ4l-pewih~dv+C@fiH4V;v5(DBuW^|gj(|H5*dCt?+)zZLS zSXwg?zMwbUAcj!Qqwsmzgm4%VxvIm*pFQ?n{Q0lG_opAf*$rKYQJaPka;>czBDSgy zaJ?Iz=QRaJpjz9S+kPCL*3-IaDb);+)Rb#cVZ6OL?ECnYyFD}J+(M+*-kMqLrl|H# z=j<;i!%IjkA;u`gSBJy@`M>@a0Q5uI#k4Ie5Z(%Ahb~GQM$j@udDzy#fk}H74^mpI zRgdSbn_?}Bh{7DATx|bR7g{qx287+v<BV6Hzc`I9KS&ORI>WI{umZIi9OnqY7^>Iu>6ja|*@ly=D zfpT>wM1qSpxG)1@OuYn&sUwoZ)%7PoeDg&Y?4MkGiC%;NFz!Z4DImN^90NW*9f7E} zIs_QT9=6&CBm}RzpT-bFDY~r%)B-UytD6R9M2sm+Lr*L$VvcieFK-WyBoZ8X?BjkK z-aO9Bvh_mDVN78wEwCVxHejT{Z066Wm662#>AWU^+x?J;0chJwE)CIxbSWiMBM#vm z{N%Go7H-YnyWOuvzxT=OyTdqdxz;xJoz|ueOrchb!e&0NB`_~reLAh~{^9MRBY*~F zQ*Cc|B*WNuU0m1NiBQ0Y^C~eocsKHxjB{9&-|s2pC0=@T=mHXw_5L}0UWk%tF`U}RD_!tCTygw-;cSKVd&<$)UAXN(80_Q zAcZh=fspp&z(IzwYi6bB_0_&KAE&Vz++IzN^n9G%REWBMyx#StDxtWeH@KWGQ$Md| zTZ@=~dVjp#4>$WEu;jH_^AtLBL+m)9HXFO%9kTlKx+!8DiQRwtqnF^2i;jt-03n)R z^puei0bKKPF@7(^^_?HE1JLc7HjrnO4&= zrJL)WD}uv(+6d5^m93;8W8WtULyFTlAW;m0%G-@rjH)dWZ0qWdpFPiQ zDOZViAts@Rha-#J?DsEk4q9>Bs;e=eH!G!qL14bxjY!bPghYLpR9hcqH}*e#^|%|m zrvCDFzn1oVUZl`aEx^IqwHC; z+&rd~bKdWE!;svqs>Q%Tf|>1i10$4XM5y+b7*U(06mR#_dpEnBOVM^*Rx@=2aICe~ z)@p5m10srG7sJ%YZL9C!T|J#nDfat)1Q4xd8j@i9inTe45zN@XpZb&If2p@g) zl|TK?4*+1xpI%K9sXtY%H7BO~=ViMwMCKr zH00d+6iU@n+cfs7mbdN2?SUmcpXO;A2`L70KxP?-UR&*ke(Ymw8iSN(7hzI$0DwO7 z*FJo)teduWu3K$>!2tna&Q%0!G3FSAoBGw1T%jLgQv;C07;<$)i%f`C6+&Ruh6qFw zf`Du2#;)rQWB)Jw<$v`XzxxNj_YZ%&8`nvg49|E)jzgMScB5beC?Da0kWqL%ZP z`tWq#nt32plJj|OwKcb9dNZW+S}&q^7rr@w_fh&j)n*~^ao&*d(p}27-rXETB<9$SF{PpJ-+%Gq&;RU40Pw4S?ce|A zw|}p#bvLEY?vHn4H&;5Zxp^a|+;l0%2tZWST*1(*!;2vh;k;Eu?1B(;Z8Zi7%rPY) zSaMy~%*=pTOT9geF?DYqo`=3;CYI1tqe$PSoOA5DC=`TJic2m;GXD=kp4!gD$sr|9BopaYq)?3d}g?R;nQz z7A>mpABMG>yCb?eY+Er0LXseEUYnX(6cS-=jR*tdG!4h&iNHe$ba|i=9?vT?m1azo zOY2j>x0f$b^LZ=hb?t?lf)g_aCIT}g6y|B@oBC;~DR6TQ!n-j&pSPQ-7ld65rK)t1 zkn+~DRSB_{0^|VBEM4k2_9=B^*Zs`T{`?>R;kNujCe@m`fw@iN#DuxF3x^lcQKb>o6hpDv5hLT6IwYCbT$&zsiIF%^ zX|^AFZ#5FUe;Bi4HDt#M4TxH;fEI~U*Ev$`$G#h`_xs=cU;e@6RMd7);vL|k^(rs{ zoSN5`$04zVtu`Urcf3y_n_s0+3H!dYQkf-}+Ei1DB{vBYzyYc2(wYk+2mvCfY6vn7 zT?jJI3;E@aLWr1i-Ad)lXu-VJ282vZOb+Nk567jnN{9jJ_0#F%^Q&rBn**@WR&?I# zVK;~%0Cp*AHAV>JU%flb)j~}3oRMiOMODEeh0yn%8N_}ZhVl0L#rOaGQvmqJ@B9-C zr{jG5V4NP7Wf1BERgBBJ5-}p0L2as_*H^on6m~HzRb}j^A!$`dtnUVJEYioogj;Q0 z6fww^whDYZ4j+IChWEvzd3PcQ6HhJe_Z^252@2Wwinn z0*=DPfQ8TVMl8bIrI-ZOpzq>^n#&htiu z4iJPL5detfxGvgMn3{qDY-@Ihh~7+@xD;Ks*7r#S!ErYw5!rG{F*+zSk3%Z8GP@(@ zTtXnC7((b{2>mej{lEB&zw}SO{!hQ?g8h?=FIOY{#_#>%o8`}Ujuzv#l}S8~SD(GU zk1>|kN>z71=fddTsJR`+*obbrAOx`=hQ5nIz#)Vn%z-_GAQGBEZ8Zf^brvzL#MBQR zOF(cp4a`g==vPyJHO8S&yDktyZqCH-UG;}fZpXBi)=GUjbzpu>%%mrpzh}- zzyIQJIprE&$7cYDL6|56R)wn{0-};8Q&4z2S?YwXZsq3GgXJ#2wIBoUu zxZx1b&ubGyKx)n@93pi=IHudH-OzW(<6N3c2<~k+_RV0cZQBZ%h7=Gv=S_q{Od>Kw z;vh`er_cpFjPWqUn|*)iLsP2;B62l^T`#-H?hu7Uq&EHVZvVl{>n>gfZed;57kB%_ z;0C37EjILt0B-iX^Sl(ofbjBWcRw$!SqS20F-9cmQj%`kP18poe&svg`twUF&Zp11 zkw%H9(n6HeX*rj2eb{YVB}50{!0TM*oS%;C)+`Ls=B>ECKMlA0VXby`n7S?!!tu0( z5H2!jrL<;d=F>Q|rZI+EYpHcV4Ylbs^m*GZ>r8apjosCh#vx59bb-%X6_%-!7>K|H zQ3wNJ3Vi6p`*&Bjhshn*thv^{iz3tqS=VZcLzfgoioDF5iVNcPILyt=(7ZW#KSTsJ z;C?zx)9zpTrCqnD#@u9^?IKiy?qp7iG)kX6(Q{30+w8AKpwiSNjxX>?3f9f##)L zrbmJ4`Lqpv>;qeE7Qr2_`y|Yd^WtW}kR$*J5)ZqpX`24t|Nf7@urmEc#FwiP0>J(* zcfxBfO?_UrC;}Kn zB&KfM9bO&|KlhDq1R`r5yT0oJiwJXTp2(S; zL_WPg4?}o3E>#^7T2(~a4bxV&0e0hlx7&a8;YWY+ogZ9M@$dd8|KZ>JyZ0wXeVhzO7v9nqQ{PxIaF)$4~N zF(KOVcpRc%?z_db5znljPVkl6jZKYFAPo5J-FuKM`iF7AeI5N>J&j)?m% z2vaXyaz4(Rh%C#x+fC#iLtx>t??jN0%mK+*_|?OyAHpYZPAq{KN^T-F_Jb3rn9_Ji zsr!|`@>hTNw|?i6ivRdO{TqMyhhI+tw^E64FO;hVv?+z9SgAFTEO`Y35K%SFHBH^s zGz>vhwNLbN*XMOjsxMgLQ>#H3z zZMpUAOgu!nKQA$IOzB6j9}x`zOKx54n1jSH?r*N9={Nt*-~YT&+`jJ!teUslhM2t6 z!_)~uVg&HlkEawuDb3urT+nGRn$H!+!J}(6kkm>ofeERBviKd}rw?Odblnv<3)A=vGcbGc9o4S{W;n1f}Ffb7z z6L3hS)}~sT#Sogd{n&RYBEXC5!@3m*5@u67jH#NNYn1TA$7eudVj>#4A*C**ZrtB| zM5eCZlti1pRO{RjK$`=36PT*gR|pksJGZz&}(py)N*MUl7UihWp4 z^L@_qvOO;=hhVM)S}mGg$A*611xc=%-eeJv7`Tpmr*w%Xr9)POC z4_-h0;#coX4Xq-=X{o!RD;Ku`q*_~ua;!E*{_MQopHFL6it_Zl?ji?*(|PTN=`i&X zeHZY(eZSTA=4p{ARW+9yg4DX*4gHI&-HXGN7()oBTn}9sBM*U4 zr!I|${eJh`zx79-=izsM>vz;2ul8eTjws*#?EV*Cj6jt0vaGc>8~aqM2Bh4opm2~3 zbjsztl{ZhPOi&a=xF=(T(^k8bSa=ddZ694vyTp&1HMi%}c^G>{4ncN-KDax)IE+_A z3QTKjFZRR0Cia!d09#&!WhDzefspgY`xI!VM@$fsS;D4xQpTbc?k@y zSuT1ZgcWN_0RV~d>9hjC=`_a>0dO}B4%DXos=|9|{XfA{lL{K>bzcbb?PRo`{6Olf}Aktbri~}+*Yk5A;Pv>>9Qd>K37KhZzT9@s()oRcQ z^^pnuc1$;8svI7kPt|PAWxwAeVr2X9dVjkgUL3|GQd;YS9EQYb;!w?Uu0t2z9Ov`0 z^(n*DAL*)EMzdR8fBpnB+nYm34c zvE5qBM_0osTUBkP?E0>Et!hivWnGv-kcco4nt2qOcKz+$l{t1o2vAzP*$w+~D7A)^ zranHN))zOsbc7{IiY+MG&N zGm;R5WWVooTahEV4}xsUOn@Xp&*$xDU+%zcYaT;rt?mP<`SY5WlFh7`4Z@5U(==74 zn8L$p``~tOYFlYjpZXM&P}leB&Iqb45}u2@(^9sn@7$?Nkr@zJwJHFD5Caj<>zZ?I zYE$2v!G|B*)J7bn-`~7{efZ?#$G@10f9F?!^?M)xaYBEZ*BE4qp)~Vm=i2stx0ZIh z9{|DCg0LYh%SzymXbSEBW$(>?ZOg9nzA?revs>-n`!x5Sdv6u1igXn_Tb6=I2oMDk zU?hTMIgJ7#FyP2}NrE7NVdNoC`D+pcNQ^{rmq<_~*lJ9gq}WqzidAG)-S%|5TixvQ za3qDHSYk;)fIy}157@x|VXZmVoMX)IOQjNQt=>-~OT~gT#J)jMCQnRIET|DFq3E zR!b?B(b8v#DRr7(9Or_RVrnWCVoZgNLaFd_HvnM)tm@jwaC38T&ifF(^Fm-(cR;L- z={NU2`H4?|{VU)46Ao{F=bcb)YFmAz*6&>ILQ1E#UVPM2tZKagPIG7~>AYtloby^K z?}HRVNu8lEshprO+NUg7wpy%f?R~ID?`Ll$=bRDC+HlO75q(P0$9t8UV?NBzd0$F) zF^gJ0E3lpJEL6-&vM#mo0L zO!)S@FDk2!{*MBsjldyf0FaVH44EJmFbIQBK9z`qm{Ll2Dgw43H-0V=7W{3@OE22=>!_dp%6!0tNe(?N)WAxuDV3nr5|W>KD)UKgi*0U;b96 z?b+t!8{d8Bbk#q<-alA3E|pa!Z>NZWTHU>_c$b?PV`?fBQ41?LjJ4X&#+#teu=kDvQs`>XIRb98%ow$MG_RLlD?zn2B~#8RrLrI9luAjZ)1p!0&H{Nq$8nld0nKcbtc_Gky}W6rkPiFfu=tcy zrCF7H)|okE7G$JYd?*B|(0QX>hRRg$T<&Yj!|X;MNYLm~C?yscT$sk0<=spPDXFv) z<2=^3l8Tvm9G8rxlyq}5Ov9ptn3vG@*2onAN^RC>_kQ|kf9~_Y|M?$8@pFIc=byiL zb6qz#!>-rnJCAQ(Iqf8rkkjrszwvOj50F!eF)uz^qe@JYdDXT11ok%}b{6694~DS_`iyGEipl(v#77lkDjh^ZLGDW(JoNSsybW>`{= zm-{KkkaF=k1C%+If{;qyEkO|-CMN|cAzXx7iD_|KOC>pGa6U4lLX21z7o`w>j;nQB zn+i$lW_5aU_S^sGzxttt!Yx+;Lv~?1jdLdBvpk`O{Fg2gy5glMFM z0{73>`{SsU&MEqkq!5kB2oSsnL?8??4f9fvS}lbTt6EpKT2<=F)h@&|_{2;s1Vi>Q zYbi*GoKwsh86}EUSErO-9A<#LJq*gI$$1na1ICz#oLXinFa#%+WWfkT0tyyMxVVrC zXe|L?@y_|=W>0_!)OVe=R<);n*IoW`1Leb`4`U(xyMO=h|BK)Gjeq-Nue@`)d$AoZ zI?Gt*lE=Zle$gL&&M8XC^Wvps=i>QkPh4uPj4>(3#u_MTc45_40Oe%e-5jRH2PGvl zBLX41#T&-^CtXVUFomkpS;%)^?6hJcfdEU)m;2d=Bm{XM0icq2^f>_*;*7#5IlEAR z&QAImBa+;WZq=9=qN$WGMJWX&yw3$n-55YBso2W6C7#{u5Wz^%G>uV}QcBjFS6_Sm z?eF~XJhU2Z2FL&aAOJ~3K~#_1!?6FkPrUNp_2K#Lpadw%As3}Y!Vp?C1_ey;6rRG1Aso}^{P^;>MCum?GzlRd00Zqc{eO=Tfcj` z{pkI*W+8|KK?YO=$7x*2F;CR;MTD|NI~Q<`1EG=k2Gv;}dJN!t(rPbUtb+u17CepR{_I+%UPrM(gn|fq|Q6mAq1GZmKhBvs@eX zQiQg8?%pfLFe(O6u9GlN;uJzCQQ|y-hl@ca2XMIKF1vkykB0&5Jk`8AOL+P1qeO#dXILnS#Krgj~sPjk_5 z?e%*i;`@{a_qy2y@7z#QSvsC`{yyhlk3s9@b$i3bwPO&N=I3bA1G-u#>9}iT_xc7rcspOX>JF!VX2E>4xLS=MNY}glAwBd)9 zGRhPE^RzVOFej`RY+kw3Rv?BZqx;v6T*UX2SFLw1%B>Vd4(z9Gmd69=MsLlip~M~KALLe;u3VW zp-rkUz0J*$BETnsN!@iOAy`@%`+E1U4#OH)k2%a~N>6F?UO*~XQh zImP|9zB7bA968kZi zJRoqKx5kFoIA>(NmE|V06-X;Kg`hnh+0EuXt2g>sh?1)iY|EJnZ@+k9{8Ih*oS^kY z5`|Ut&-TKgmU|w2G`!{q`7wmbZIcoqJgZDYi+-d#eHi39-i+?I~x_Pl?6zarT9OC#OLzS)B)V&Hf&K zfFZ&oR6=4{f`?|3ABr5p#+MKdT3&9F*Ffjv5(>qiu=mzV;@4~&Ny}V8&dtW851@q@ zMO-aZXO<(Cw$b`SlnIn-uY}y@zmrQBy7_@a2RGCVz(8fR4Z1*C%tR$sKihlUiJ;O> zx0?eD_xtDxjWqQpba{H}4X&W0tBv+<%wE+TY`w~1$NdD$h_G;_ATOVe!-N@y+@;UuO2MSNts{!M z)f_8&jl|7&Z+$xWT@&Q{`Kn{5C7Q!iNl|nk&Oa)z!T-9A~J^%Fg%=~<$ZN+E3 zp(k(?8?d(!n@rQ#sRXE8dcJpDtxlO+s_P}vB}|oxB3l;!4=960-u;i4qioy7_x0Yv zl%QFlNtT2@tX+JB-_+YS_~C5ImMj&TW20jN`)TNL(!MT z>Ix@FuY0lI=j@nt0YV+2`dCXcog z?w$Jldn|ugm)p0pjahs7ME0qsnfL=af%|arSl?POH1$x0EZ4KeF-~8YtIMVs|LRjm zQ}Jrd)@AZm^CVJ%V_jKLCcxKYtkPO3EsK*ys<%sv5zF_NkK%zv9VbVYq-|+Rx(x)+ zN*@%JppWa8r-vseZhN0{ z*4tuhOHQk+=li=$t`92;->@E8{-7rZtjvxcdKw3v_D=>IW*{QNwGQ0hi{{k!@_oro zJ800qfEhlBO{4(GaOYZAp%9@l@rKllhJj)TGne>!j2=EBfs2CtTo+uO)M3XO2&^wK zK{-;vc$;QkLdYOSg@t38EiLLi$zd+>hr42iXvUvvc!HJM>!(9uGmGAb$0zK*{>8!c?UmtsT3`dg%E zqG-%mElP$(X`At$iGa*xbeuNqT~Zb3yIo2eUA2VohwtMaV>9kPutMx4X_rf5NoT*^ znD4!tM`)CZMrOkl;*6qqR3@iJx7m`>L2oN?y*cc4*4n(7#Nmd&4U9*<(`#BKEGZTV z>Bi8kvZqAw7G)WExa}V}yi|F&G%__@FEh*znC$M1|JNgb#j+PkvfMqf{kXFbq*W)! z(o^-AXo@rXHa?fP`or+ine@f$QC4euWQpMf)}5%MCdUVLGZmuv?QjR};^!i;bq&vgcDrR08PVC*`=tU-aY8 z3n|{LCqOAk?-vco0%H;gUuL|gPH&~6gg@Gsemk^vj7aRWTm1XieD3AdN=3`bl(Bpu z_;r!!o1cz!<`M?ebE!nl1f~9ce|aW>=Icd?_NM9Ya_vjA@)e?r zyV3;TBeaa~4mUXnaW~Dx_wsq^8}oS%L|G7KX$K2ax){-8Jwq`(1>@dzU%^Nj_EdL6 zRDQu&K#mv-mtei{VGXHph_}sq(W~L_zDGr;i39V}e0u8{zeUqiz|O&QwQRQxK6?q# z0N|3|^HIC)t=HljOPNa@mcN%#|T> zo`lmD7pK8bB|_mzp3Fl;$_HPNKO_sskU~((d$yd^QwYINpyZeJ;tnVKH7N?dsoZua zm4LF%5&VJ(3A#@%!>N_DP!&Q~nU)2-K5`}=V*SVn8Gj-V1K$S|;> zY34NOjt;HJ6zUx#<`HTmElB|;T3&qoWhf``3?8DCs9rhtu%h`W@pK``{QAepCDAtW ztU1Bx39QPkoQXlow}D?Rg&Sr#*DuibAJ{IzSKVN4M&MXdUSX3n}y}I zk%>l>xu*w<4KiF#z1p`)m1`;8EmW6F4aN zTk(Pe5%S9f{-iSS={d-1Tz8y-Z!G&|OyxVu7l$3fgtd~XNXx%}h3JB)Iew^DG%H#M zpBKG3DK$UuB;Eg`eivDjbmGD|^6tV1%jVtjs;t_=Tst8>`wb5L+{(XF$)2SbF3+JE#ca3g9a5 zJ1s4Tqu%J6`pmVXCJh&AhD%b&N>a@)zh7U;UnR@m=;k-WxBSEIRkgR6y*TU};@{fs z-uY>zSJVi6_JH1AUW4Uy3exeFqJO*DS5A6;w*{95?O8>CEK(M9aojTb9EV`FA`07) zbmb*%DHiEH2>=+A25hzviuGsais zhcO{ctRNOBa$lhg_f=MdoSF(z59UiKo??I$!TI<~zm73rZ$qfVT;E*R=LXLHE}E;y zB+=v7de~T2vU&c@4zN~fXMjLdWJ37>u7awemU04DMylAzepAKA#ocg*%w46AEeFS> zX-rOBN1u+Ui>wViiskfta1K44wl39KJ^$6dW^&uAMrCGzYwXu>OYu>Xhd^H%e$p^H zNf>0=!gbOAlv2FFkYka3ia-YEp-}r}%FFDW z55vuzb+S8jSB8vj`pZ8tobGbSGDTyo$=mn}`kzDW+(Rj7RCW6Jik6;Dv%UZP2#ZV^ z6;e}Cw|{tN?RN!TXXA*g`J1!tGnd;if{M83oc{Q7LyuhZLXM>WK_bxiZ8C%B{dQdn z9Hy~F5LYv`MuC6`RTW}2K2OP??Mt;>X7|3i8Cem$e|PKf;SUi{FSg>nP5u#AgRPJB zF7ee0(ngb?w3KeX%2%G29DL|Zr=$AKa0eYt*>bvlavZ~?Zo?=6Clf=QgHqDc{mhys z2O9a-lHdmmb=WFY9RVJ;|3#r+`0FlPr~p^<*}`P?)@AeIaPnX_-G1EjBFHb@w%&;e zAKxr}ea=*ivMf^(8LAGD`rKV;c>E~%Mmt1kFchX zWSRQv!QH;a)={g0Ur^4cou+Ngo{H+DU_Aptob(4s4?y6YD9B8HP@VafE|G9{bvV}_ z@v_M)1HC0eGbicdohDEg^L_L#Ls-;pgZ*R@AKpNgLZ=P1JN#Q%#-8H-@j@FBBvi6iO~{&#|r=~UBp+Iz47|= zf~iUrH#xjHXMQotA1eR3ZXqyhqd^i`DM(Ral4a){KYrvk-r^g?E9{Ma7DX05C0-PZ zkYyq0URYX^-+$t~BX&z@kAqS+w)|0*!l*`+bj>XSd`C3*kbJCD5I?9?g%Z2-lS zVE@B|OC41U$J$qV^8uFvk3 zxIdL|aNMlk+RX2al;-uu@PPk(Cg<$C)Z)M3pVq3@31P*I-}EQ-@>$8E6Uh-q@Q~OJje z+nV41+mj#DQf+AQewjabxv2Fra&J!IOud568}e^WYC-n)%YsBvXGur^pho58p>TT6 z0{aN+nUdUn#c-wCDjcRo@{r+u2<5SUDssZKy3ty|%`@#BVbou*(5D9U%gT;n#aTmr ztL0;fy^K6r&JBenvxuan8Ge8U)bYLg5LND8W>&Hipshz0v@D|Z;6^zc8l>9aP#!qY zxdeg;=Q%p`ziz&Fy>>UAI!|=;b7AA_74@7;h2(F#Q+3lX>%%fKXW~q4xIcG_IiK&I zOXF_i_3(*}E4+j%ls%OAGSl)1j~yweTW`i9X{!yCqNxz>utz9WMPJ`?XVaZtKOb#F z9;2OC@2hFGx)$Rr zRvKA>c;d^we|AiH+89rcb>8$SEp-IUv4_M0YYui7a%M-8*JBV#gWrU>!*#h*O&%Rf zi*|0?n9e_CN{;DVHR+2dN^R9v>03g_ml-^wVK-E9=$q|G7#RkmuE?dp`=?l!{H1Y_ zUmAU$xC48t;WzzvWXOSD`@|s@+c=kBP2UTjp83AnU2pvt!D$X8TPk|9$zM^v_*ioV zHNeHzgY-az=tH3!|GMP-T6Cg~d7hE9l3CT2WmJ!nU-|EK?*`7lQW)Y(b>bVQmt@21 z!))3&OLzte?E3|GgnMkD|!?HV&PP<3(d(>#mkVx(HGu9^=yC#qROCla>bc0(T!KlQi9L2ZF&G(q4_7;C`R~r6j=XOPH=dRd)$#a}V zJMO`+r&=xo>rmd1`<$N`EpQr8C|o!q3Si*@;p)avz#;VLhBphwR9oJ@*9ANbkWdUl z&sP4L=6aO#-vY3tgz$H;Vf~ZJYp;HN5hu0 z9I11iURf#g?oBfz!oRzBDqWp``(l2b6JRE*mdB2I8tUYId;o!Wox!#5E?TrTym2*2 zrBhyd-hX%)(Yviz$0Kh}Z+QG2V`*uSgC2^Jb-v$md1pU98OdjE>gsG0ND-k-MUR9G zLC7r0K52$A*0|vHn!W;55nNo{ZQFqiCJG8_$uYP2n6#24ETR&ln&>V@pAlh&ErirY z_kgsX8O~lCvwzi@&4jgsleRE21&l5=s*u8t*RflJA__kKYM#1ZLw!sGqqU*oYBD<&4k(IAx8tfh=V>)Zhr}57d zJ@<(Q-q>7K2r!glBMBW_k2!o%_n3&sR?`h}_ZoVTLSwWIGE3*R)W{1k5|FdB5V7#D zcLV!bb8GZ_Ow4|8gfHp-@t6Nzf~a(g&#y&6soEW({==|N)9>Y#o9!jR?rD43wF1&i ziVRkLv7fkp{NOMT+OXFA5US+4H(YV~_gQ}HkMl1qaKPUP^Yh2%mjmmuulfwXfcwep z(z9R;FL*qJal$Yu{csBXL5PCef}Ks=1jUeeD#pY9zeQS2Rc~)_p}mNJ17DzO2xdMj zqM=EK3j#nrKx^=mI>k==`~q>I!BhQVd$c-&H{3WYsh|KVL&i9)6vd^)%w5P%9qZCh ze`iTrG@eLYvnk1RXnm@yAE$*-b&{+IKGJDDY5mu8YyD4LMeB?cJb%)i)tjgu8-!-b zq3tYSd|9c0KmhgGt@NPWHZq@Xg6K2oOU9SwjS$ldj+K#M$rQ6yC0?982k z0%&zWMuknl>U-xe`1u@8b9@{D?YR=QPWOUsFUSD@=s0Sy6=5f{w>PV8qeRUxdC zF(KSq1A?C|aeR13q5b8X?a|RVM8#CazvIQL_14pNnSbrAR|iG%W}?J<@n&jym8*>| zQMxV}HMuBtD@%L|c?|<_S^6B*;ck*Ku$t9~*eTR9s@L#T+{8yy!Zlpw>WwNgd_S6G zJ2&iDegcyZWX{tAvR`6T5EiECbsv9x^koAu{wzrXq4D;Q>#LI|uYB%$R%+k?42V#r z0t(HTx>CfKSDEui|b)`Ty4f$US|1RNQ)1oO6Csw|EJ-eI>qC zK@Dj-UJIynqERjwQV>Zg979Km<1#yQ39RueCDoLQV!w1_Q$`<5U;L~Yg%5O}m39VZ zndH}VO(FouKAdZ*-~OK2?rud!ng^PZ9*SceKT}(O))12)U_V~($1E(I%xFcmZ)Ure zbyp=qhJ`UIF9g(qdm`Eb&{P*giI9C!f~q>?#ab`Dnzx@597btNIL}DQ%%H2T z4KOM$m&9S}J}#J*8FM{E!f5bm0LjwXNM2B0Tc`I{p^?xl2H%D8Q~l$e?P=@;`TNg+ zLh_KPD7nyhHB$HZomO43j3BOZcM!T7bC^8O@MBvGZ|+Yr>b(A^e|}A(A@+g~>#nF? zF&F|B5I)3V5y@DBHa4YJ5@sz}T;-vb?s0aqGB>#6HiqKfEbB<>?d~QgZx{Fgdm8Ab zNiu0~Ia@e>`$Aob_q&~*JrQ~umu{-75%snB#eO@uU%-Q?mCHpu9CLIjvx2{Z{nb_D zF3?qg48hcsiZP=REe>hX;$y@6qnF3+^(FZ4N3DO=TMr^eg7-&amXlq742n6Q9x6{` zkx|IS@1>c~Y zQR^}R?w?B|^59Xzd^Dt@-R;`!ds#faE6=F{cWj7p4cs4TKH8)8e_xl;eI?!ObZAfP?&MppO34RZl5bSwOFSF^i5 zzO@dmXT)FmhXgBXF2w6U zwDEf-*bPXbrInyvCH@1a z$Dfi$sp%drfHqKT+mEsb8dV8rK53%$oKaCf!Xc{P~pS)-?f2XSJ&>yW%;j!Ra zR*)38OmYnk&Nv-kjZR}B_4FIVZfT|l8z8jJYrT!jZ9W~`YDqaY7Zl+`N6%TLX?ie(WpWVmBYZ8X^}?xW^U2T`dv9Q| zD<0IXI&PP@*#pwmbLI>_7s@%S-lb~FY59{bdS!gQ<{0zXrS}Yb>~Hppad~;cpM8BP zd9*FsAedFe7Mx!BzHx7;`!7ZdP}EY$>MVtHQx7O2G;>?q(HGM+@l~r!(+| zw4Wtc$MN+6Y=gW#8>fY1r^wyiwW*GZt=kp`dJtS}sa!_Z0H_#a8u~y^ZtlYid@mpH zzRKsj=-cbMH7RoWSa$nMsW;2ES4G!9bFL`0e*9pb(xLuqRrluj=Z3opqfVk6qn=*kHRcBR2?==coTA^pPJrL0QU2dXvft;36!{HebYUT zvN8olRj7>s4nX~Bmc0A3p&kC2Ml=kv-P6nA)NIhO zMKr(YVF@1kwjHVTMh|$c>b}wQt2@|Z9jn|PU0E_*o#{*~^Gq8-$i_QXKmA*sY(`ba zc!~|anAvfsn!c#qV;i=v5e~cYa}`~^ivg6rR`dfG=?;{*mb*mWeoeSbnlcp&y`Mpl zg&6c&u7@!kO;zt4f5|$Y4EDlnN2gOlFpSlMHk@N`FPcTw#2w!um2gIal;K=|ttXqE zjsWM27mr)dZ{=JZn1j13{>@+io8Jq9;{N60>0+LT4L8)!zeFa~qNY`#c_g?dapyFJ zfFv+TMcPO;tgJee;z^ml$OeH&-6SzOBZd*(F)D+zp4KG^BV7!$XfE81j$h=H$P`N7 zacOi_8Ha0RkyPZN_Z^d(r0`tCQWEU1McP7(Y?(i_YEyPlqbCi?pdLYeqyO@?v7QOu z>})MHCotsAzx?B)^y@w$x}vj_{+->QGyd`#D$#`%wY`Z^8a6EJIBl#YC;fX_zNqlT zWwFQ|_rNdqI%JS=gplbYW{m+)ku!1`QAKFtzLyFawWoefgu#YSMF5rxs=nXfBZr+5K1Qzm|{pChH?%gs;DM@J1rwRL}UJZ9E!Q%_`vE|k_WbV=VA%v|_ z6{$(u9s7u_%O|u!k(JMK$%Nqpc8+B}Q-A@i^VE%EVXhw=M}WM7gg9v@B{>fZc19#D zte_G=i$(~56napI_wHJDrT5^d*4i-~#u}> zdZ~Jg9Zf-Wcq>E1x=01CB=n{)nHWE(iheS6Lh%eFo`mV4zaQ92|Jq1<$H>9e=Vr|C zH#A1#6IsRa7&L?|cjRVU4ERQ@*ov-T96cSH4m4cK@n<&M_vr~~>0;eAA~Hwr zbl?_;-=hEeME%ZH*4}9hQVUfPxpkT4<{-2Iu)!UHJ&9KL6C|{k9!v%;u3#fjZ3RB* z50&|3x~s}+Jax5xdQzllQ8P}P>9&qvPUr(qnE(f?7uC9CX98Q3fh2+LK0bk5JRw7G>H6RA2q@b zbS}5l?9C}7HnrdO9GHWeXMks!YbD$@-qo1i_gF(tbDV*h;O+bxju4Tq^6ViKdI->`S<&LcK;z3@%Sfw^gdT|pX_?p z-r++7aESO12Z~PJ5gA6eG2rWJj#cc*)0XTM4YxMwLF!uq|($xZrh zNzzrg2PqI2q<&_@_-d!x_SpF0d*3^x(@q<>&w0Jpe`kcle5Pq<30ar(I*U83o~yh}6qq!lzSk1O+5R=DK|9_m9z<+cWTbqn2%C-$ zkv5_|Gy;;p1X<&&iKgFwKVqX_fAW9{Qh=G2iG)ef5j;X0AVJ*zQxy z%T5kHC3UXcd8=WSLysRviagAi{T}iC*6pb^4Dr`tXI0d6OK zN{SY5Xu&1iaN5&k|UgdJZ0~T-l;0f81`S1*lv^U ztIpDHr_>$@^PI|4M7_(an^cRtp`yh{AkZ31OqbCkz>r`80UkXZd+x)EgQh+Np=uNt zF1_`2l7kPEi2arLssNFTms^8mf(fJ~9S>XIM= z<3$K__$W>%sTYSIU9XO@zDmA7J3OxQB6oLv^!26g^w@E|F3Mq}$(+0K@{bEY1S42{ zOD&z58m)`a(`SIJX3cHh?)YZzG!5h0$QZ+DYN0Bk)VlBvUkdu-}SK#Md>eH+@`Rvn?)WA z=B^W4cOMNH0E)IkziH2VCvWz(D?2{2g$p^?+<*%f6KaXFxc|5cF#9sY>fKZxL@0jU zL9wlvd}7CTYR2+G)*8~DkH(1RZPX`CloRa%!K|twTiCbSWDZ%3YJ>IAI^{8kr^19aQYocHX=)$&j zsD-9+d(d1$U`24JkqqMA$Espmy+dXVo85S0uTHeY=%ER z;0egYO<)prSR~gn=mDx|8fR$tT=tXC?=^}eR9>JqZnX$9uE_B*^Ds!lNl~7xbaU~+ ztA}s?xL*Ht(B9u|dja_ow;p^nZceg_^8fiSzBZsflJ%F?8qy(?se~hvcIF|zruO5~ zn4ztyzHa9VXw0zq*h)wrJNw&KkxQB%pel6lW(Qj-yA|+Bjt(5mm$zpL&y-tS{7_cS z_$*Hg{Oxcn2vPZnXcztU}+lM6jaHxSZ572CsO; z-!{9iuYZ&7%~IZR+&FS}j&`qq@W~&zv0AJf_&jXoNrf=i2ulY|jlPkYdu$D%zQ!{S zWK=yf5|YryvSji1ce)tJ$jruQChA5G!y?)ws#|5kMQK=JJEy{uyr-e8%9q_pwy_HO zSpis63w#TDa{GqOiwc8@AWINFg7M4oS3vy34*z0?tu;}TuNi{UO3=3oVEe)2xPtkz z|HR)X-rytDWQ~f^3OuvHL2bZy;*-tf-D#!y(mW&k{iP~_G@6cyt~C!zN;v!gK<%}X zXt7NRwul8dPYG#1{xGg#1XcMQ_z7qx-5B)x+5{)8lBP3675(%+h4REW^DRrT2gl7& zcNJ(a`IN&1Gsz;;haZX3kJyCm9@XAM$!!go-1dFlmdAVV*0XO!D!?@3;@eVC40T^U> z0vbbG)p01@9!>&q+Nj99DCzas7%sam4kj|`JMTUTXj{hA3jpD}5~3yz*E6oBzsT*p zhkpbV<;)#m?+jj~GE@0vx!XK&rv*tOWUQY;z(w4^nkjd7J7;>E7;pJ$A0C6T*`GK< zeq6f+YrbDz8L~x`0+KcU>Z!v7&mtQ9Q-9k%TI?n{fEK6REijCDAh26#^MH9+diz-D zxdyL;rZGwRz?ug+5R?9{Dcdo3_&Yi0!uNXpO;dwz6OEe=P&9P?%|E2k#H{o9i<^m@ zIyX61%Iwhsw`-8#l}`2lTwZ)Ao)BTybt}Z2P*fA$HSweh zjS$N(_-y^);Hk>jKa&3aXTzb&fg^A)58Sj%cw#Rre2PpZ_dnfPa7cvDJi`R=*+v%O z^UP63mQd;G&Rnb8-~HBqZx*}qJ`eVu9nSa4AN`q{+Bn89{JgwqxC~v=wT~GHyJZRT z&r1BZKFih-VG-`v0YEwQhH-I+M+Fw#Zf~Px%6c7Uj~+yNynBm!;fTIRdqY#K1MGUN z6W-sC-3=6y3l4U6ZhpL2PS&BP7m?+M;mSp(^WvG;H={Dy)@PwR(s@22v=Z4*PnK2| zFWPNPIXx-+)UQWxxu}&|p-V5m%}0(@_@pu$e-*@u>*3NQT1NgUNN=Tq2;Wvd-U9n& zDY4&$H!1u^`eo@O(BZ6nX~_IIA0nFZj#bUiEca+Ca%ZRe!|#7->XtftH~g2wf)Fy5 zSrKcey<_A4CPAsCjRK6u81A~uf8gd{QE955q;vIK#Yw$^FNr6v{=9K2oNa1szPSCv z-A+xAeUhh8Q1JCQ3u?pVfAe6AFOnt7Rmem97Z10=kM|2}r22R?K|SHi3U0T!u&=;= z+IDe1Q6AC2yeuw6B7s@VZzoWSx_bkwDg3!s3&Rvb8B1;sU@^{qVgWt`mK}wQsi5I& zY@u*zAlvD}#i;8OPpoGbM1QKkNbb;F?`?8Lwz1DU;D=`BZPDZcvu-I9y&PRiFDn63a2_HH+!Xw z`s}j}qqv*h#i9fxW>pfY+Q0VVLb?0bQ!}c@m{%5ZyD;1e;R#%fsA65V@JeqBjE_Zr zTT$#oho7ak(~fzIc1nGrqmoCTJ&EK6vr}-1?9Xivf~#v=l$`sk!_WZQA|v`onSFNQCQF9`e}EoChh=&;xEgoM-#l(uGIK4w zMq;YvQ!C6bEcFf1kwLCMm=xwexniB`D*!li!uo#SdUnD0AG^CoPS9I@vR_EhQs_V0 z5VR)iq5I?L+h5!0sGS`vzwY#LM9(iL^0!?3roN^<)ayFPIO~es`?2Y3?(cp4E$``f z)b=f~iO7F@GS2haE}aJg;h#G1J5jozNz*x1?h12U1(J;N4}={gNNwwgv1OG z`|BZDu~{qY^}BiZCs?AyQ`B`JIx%dwo?<$dH*^eM+pThvlRCD$Wc4?x9+KCM-V0o6 z&*vX0+gT)qw{>XMey83Fo&Fq2al_(MbrVM<^0ARVFi#qEaa#MX^IH1gmOYj?;zkTT zQ&ta|b7Ytpbx0doQFwrpXJegjOEH4A&cUKR)H5Xclha6D=hvG=OKX|#cU4@}4%+ip z55Au5#+MUQ5^~;`l>PF1jwUos1&lZc)O3Cv5fyfo+=5xwn9?nyqUb&PZpNx`j9>?2 z9QHmktB92QH3t)A_`t5-IvOCrSkEIK4v#UQU%BvoVUR9Y-vAOwPr8fxYBB-^y`O!; z-8kNTT>PvY8^I1U2gcX2jRt0?cJ3VbbaXPBA+iN1+4)p98_;-g@69cC>;r+4KkxKl&}DzHGo{( z5} zcD>j8k}r}D82Kw=@pmX3)_7ztTUiD>pav7S>OD0=?>JFg{~hTfKTet@f?4;X7xNI&ye60qes4Zj6$ zyOWjIyn`zCBqiUzpf0Bym+fw7035S8io3-hh6xtS?OsB25@Z#IL>=D zrgA(L6D13vka7$apMu1aq3{`)0YiQY*v(0}_NiZ=Hu$EW+0bO?S;q9>fP~{*9*eYN zw)avSw*^Leom!!TN3o0Q*HYVQnva0R`L_-REmIfmi5BcxOeR`SJDdz}oD4|xw8bfUvx539`Td=q>o$0=` zFHH+<5BYPFtCYs;S3mg@3AMrTmp(MI$}` z%H89e5iAt5fF2;asj12|<|)NDm&qIE(%}K=HME#oB>&*ujhSPYC7Lhg0zzcv4<$hp zTo0!m{vM}E^kjKkq;dKtU*Tyy%@iKtuYdEuIurj0abv2i9F{v<4G8(Jvu^O@zF2+> zzgU`YBN$-$;a@98nWG z5}#vgJcE#K4->~buX@H)Iby2|&HK-AXMHsKwX(OEGqQAUMLqvFg?nYdRJZ+R>5OIJ zhmD6TeWvkO0f+d7y023&WamS{{VNGKwKaPk>I86 zp~3W3ESf6pM!?q2EARukgSUI8)A`F4S=)=(zi*`*ZSgAWm9*zNOmqrZT=KqbuvL z*+ClWHt2oGL9;YN81=#jhqS7PrLsoB>xnmlOu3d@1GAj7S~KnzE?~bx!&4);;~isc zWD{)lYd>(zEDlGXn7ja~3QcaY4EK%CQna|G5m5Udqom-i$(ZJX&w?`>g^H_@V2Rk6 zz#4Z2do(^T_Ake+Hq0HglYXC%kY)JA(@#9#v;X>>4eK{{=+8c zyXkLz+4zO<;?@n=FvDJQ@ZRCn>+hWHIWNtITmG0fesXY#!jmP9QtJV8K;nq z($m?-H;W5XCbnPtGkq`rWc)|D2<9KL<_y}T*;o@wPpTSg5Ifcv#b@sQzZSq06fR)2 zsJa;|fQRy>fDmrg%*wY@ZPIOUg1;--{?Rr?3iF_4yyGVGB zF^%>Tlp^-bl3nVP>fLFeHczauWxBpE#{!E7%M{CQ;L=9x-^06yfKX4zwG`tp6aKm8 zEQV=L4Bj7uoz$1l4;Pv2@)4D|$q4^1Cm_wRRHzs;;aS;6tl{}tgO0UxK12#`)r+WtMM?vpkonNw9c6{b&o<@Ea6?k6A?2oPCwyvxF6iQq}J#XF5zS>BZS|Y1v z(X8+ZxMGp_s}Vgr=xG?Wk#Y~)-+AaP<2U#vld< zdK0l&IB^YolltRcKhja7Ko`PK!GnL)t;*B!buSk8eE>m@AbxonO#LI=l}TWnS+<3>*$-3jk*!6&OJb z52G~>n42*|Ec0=2{}%P{q0qWxaCWl6h%;6D9A1Ey0?jKlpzylo`C7)KpY+e2*?R`; z-DGK5W4xMcyU_AhmYG}lg43~LJDao3z38UEravpGvO#-GEp|dP+qR_9jhpmAv+%H) z%%aTKiIcavB2hjf!|KJcxr`u(>3=yN%@*fA#Cq?1r=cRXEkd--Vho9*f$=!MVhpYH z{{aU<_`VGU;Q=FvA;2sS5FrwhRs$y)asti!{?VgHHhODf?*4Co>%t2+bQ8qp7F0#; zE1!M%o6r3;&kbf4TXJ~+f>A23^upqNyA=|QI;F7~M*$a{8z6(yY-}f?FP54CNABcu zryl!Ua7Kx<1|ipM#Ll@^D^^CQg{n6i&3fb^VAwSR?r~}f?q}(-yN>uF)qeAXAN}<| z`IBq1YwYsz+-up>zxq$S@!@jxg3S_sFFV^d&wg>k#&z@a9zcIM)j)P!r zR|#bzmChJBciSW1dFJhPJ?>q%m%SuS675X2P;XV*1|0Q!gQU>6?OQNl%CdBX zAcBxZ#u-W>OO>oDt?l{EK|S`X(j1(R5TjO`pdJ~Aic*zQd4wpdv^EQKA!A;xHcy$} zSnD0T>)78c4%Q-*a}8f6a5Hzg)YX=PneRX!!! zY0nc$FE_?)b_b3Sin&&1&r&nXi+bn*a>fw_PHICOP=Hictvcx>`CUif(;uWBLWuLS z>fL(eeP93U>oFO9Q+Vpb(YKy^wM-quE(-ZpuOt{p0!2cA@Hul;C6RSWUep?K(n~`@ ze|lzf&tfgh3?pREo~BgFY0Wq(Dr*QuPL-LgMKM7t&C6QEr3UH16M@hCRudK%4(8;* zH@^P88@==$c=Tfr>Gkiww!EBl)ZzVeX_+$;30I`0DUFM~z=5QMTI48#G|kJ(URc{a zuz!BgmvQK0iWnzK8b%;VD?j#)E*ZlCk4uY<)rck$i}Fk^?A<#kvIdP()u&?d#POS( zV%{`vR)klABoFdDe&hqUBvsPwmd2Ra=bj&XoI07OrK$<}4TV=7b(qqC1&)3Rr4f3+8ltma3Old!nQt7I)xzuqzB#aBeLq8Zk z=bd>`UP#~fq%wjrYxJP%W9l!=&Cf;kS`=+=4IDDu6Myq;zP?f2=yhKLFP}=QvVQM- z=9NwTnpoc)gq}wQTkDy9bAFno{Xwz1oy4^`NpwFc87JKHJU`@|JBNdit5Q+nNv$yz z2vaGmIP{!T(v)!+%+KweueVR0Sia}Z+YuPH@ZJ}GGB|nq3a?hbrg-g)EX&&OJpJC2 zosIR4TswTv?R#=1Sr9cmIJ2_FxWGKn%6T4lm?&rCI0Q?TwqYEUg+UluM=Iq4KeVy} zF$rPEx7HD3tN^I2A;4jICj&v{;|xE>-*!XU^?<9Un=k5NJ?2f%UUQ6`*m8XypX zBHFk<7YKomu{gN6*lsiiS*PAS^wKM;)46$Z+LhpDMfg^6Y`kpiV;6mg4%F04} z-X|_a_Q%iJ8@;|afhV6>xUhWOJHFfzSoeZ6&Ekz2(g34HM5?~96;pZ)1+2W64CdW{#AsrjA|BrmMs796Ui4MQ%K zCX|(BA(+TZ4G0agj53s#<$S9ZF|S#VG}v@d-gWz-t?hLZ9{$eXzmuMvaMvBlV!Uu- z{X(AR>ucq{r3fJr`&3)&tPvC&3z@baq1se{XjSHz`eh+06WhJ5S|dcr#4XYG_LN2i zhL5?qoMFw9=;C3>c%<04KDl zB*N5aV~vrv5FQJ|d1tFetzEB0gUyZhTof^}lC1vdh44nN<}KmagK^S3x6#jvObadu zkfiAEZPg2nIVRi}o$eqKIInbN4WrbLY7AJd9)m80hkPDKNX>ctlsNi!>juAB{L0U@ ze|mcL>_!J;kd-PE71mhbQOfA%)}R%HNu{K8QH=8n?O9rK78oUSH8va~Et|uP**h6&lCt>70f9|Z-P-Z%gO;MV%0s_o{wboJuek7Pz7mS&*sMlJ8 z14VjsD|dw4vA=Pyn>XqQzxkarH+nU12_OIP0hV`5SDx73vXyUaXMMfgzi;0l?Fo!4 ztGVD9u+rwp-h)-zO)UxP{?bC_qD$E!yn#v>{tHy-@m1&XS{9k z{tw)Gq}J~wnp3;7zFAuB*XPqz3XfSSiIaQh8tqzm=KLm)Nl6ZW=bKmlw4k>$KKI3c z^!yM0;NuUzfBC}dKo@}NRyP*{C%Fo^kjCs;Xw{HOwC$B<(AzqA=SQFUiyN~c_FChE zA3xS#{Z=ceV`&=Anx^dJxwViBKgQUJ*yE9pUpuq85U>gb;J4?OZut*?^o<++uHS{Y zDTLP?KmR-bd}FJh=cU%lI)@QvjQWAUG++PIfAzoK=y!Kr@yW0LW~ZB!Wu>)-;SExp zM`3ViPvigjAOF>jes|XuPk#9;gCs30X^cjIFd;(ldM)~!|Ks1@=(l!V@umOncTcbO z(ll368EX+jln~Dst!C}(|N8fD^t-#R`0Vfgi}lTZo)=0D0|lat27$jY*Z8yl`G2|5 z@9tfWn?iV%@!>Cj`Sj^?Nv~TKxss(;${KC0vDP|p-~b^&2qT0s!I)6WIOU!ngtbQV zj-yAu_WSQ1=YQWXeQ|YpB^~suGS{-wdPIe@4#0r}7*c^T#)MEt8E3)^!noO3|VT=)>gfhlB_ktj*%`Yyz@Mr(&M!)^5 ziQ7N<>F)M+ktM1swW^HPZs;A(&JckxCL=1i5MB_~8hiHb`TigM;f;R#R}G)~t*^fN z+UY^BQ|6hfO0A_e+8X1Wbm z_13-v2Y&LW@5syYAOF%nIsV%5L2tXtGg(daZ#M2b=Ny`R0~%tK8DK&&Wt4F)JQ2jT zX8Y*vxBcD!{eRuiHC-X@|Lo_N&!0>C-Kxlj*`d+OS#6DV&VscT92!S|ho)+XCf-3A zV}g0UAI8nOg~uMg=ij|ETL?!#@pD^iYgyV?MW$qBv>bYev&K2=tOan+0UD)8L#x1m zF~JxUI;4VfA-o`n>g~m)6VH78Mz87JfSW@2mT>1MKfShmJ{=4_ys}CT8z%7!w)gD|SK_8d6)@?ZSt8@=AvbnxmqRaqjdQY&d@>mF;Zv*3n)G5k2H35Oms&5+PI zNur}9iF-j1*XI`Zo&GP++~`$a7T)ver&iCOP5ZsFNR=$j&a4QW9TkFZhj+N4XAH?0 z@qmYc0#imAW8C9@6xEwc`wqPFwRcq$J_w6XsjS~N9^T&-UWEg4T*yk}Jh)_ZpWt<96_+eOU?m2Mi_+NePhOYQ^ z@xarcKYil0q}!?Tao^7>m3fjN-=J;iI?z z_)p%Zk5@hV@lURvKbsA@Ri2IFzEQ)v$65o{jvE8R+vRtd#F&DqcK{4|7+M7-g7!6y; z!`TWG%nO33-db2%`R;daZu1MoEe6<+AYjk%?L%isCtja&C_eEOe#_50uZVRw7I9G5;L2{d*R z_h&;t0F2AQSs|SLF!pvpFzOqRn`4v@Cy3mSqIzrZ!NYGWIXw3HFPwPwl|gs2%2HVs zT2xz=2`?an)Y@W+32URrabIO3lQ3s8BjJHn^EBhQLR3=^zg$E{rUg) zuW#7OFT%b@KDfQUoF#o(W~wTUR#vN-aml0+I;n|aHcCvpqr(Q$C|w-d!?-{sWH?{P zlripcFZAR3+~U5K?|%EnuKgW{n?m>|aNw~IZme9$ldddsC96@MJJbD}*tDCmY=9Xr zpJHt8V~-#9KSs&#xLG=K_))Vo3Tw@!{fEx{?O$KNHNOrPkG*euW7G&8cK^mR(NPsR z3VAT<_KX&M2_A-1A#gKPAT%D0j0S z{*@no{|Ei;jWSDQnGbh=SfiXVNX<<)jg6^q7jB3F6O)5;Fv$S)-T)3OvaS z2xWvZ#(nOGLEK!}d*J-rwT<*P#LX+#E(;Gm{rL>R=JL6$zg^|2ta2^O;lRU9T;18R zp92DL4gt*k+Vv^G^y|Zkz|643S?ApFkz>|bV~w%K7%i17)1+U&Z%DgbHvl^bTjoZepy_Mr$q0B2UA82aX(jc>Cmu8^Xh*zx*o$XV)&A z&imVCmQ+!7R)>>zsHO?4gw9!h*GEWEfgNN>Z z{KKm+zjQ;WcxU0J5dLiJefR^XUVFK}yM&FNwMPA6PzfJn3$g*+5mf8P|d{ z*}zc500G(|ftL<;7gMo2KbVwL&bd)SZH+P7P6OZm+aG>p^Tc(%d-_Aa_N#qu)|bzu z{p~7GR8<&RjtZdR_-7RKk-K>9mrKR07!1ST@C44Nq_EZwH=bB6RaIrlpmFH%`#<%m zbI(72J*l|!Q=cxtZm%!rgKm|lT8=uyW=zE}6`0v6j4y+PH=+U@0E{ZCp-EV4oiWC0 zqm-(OLBHF+?e=`_df&~v|IrV=_R{nHt+gWQ%OY1*X@*U5tDP}0J|eO+CBm0M1?>KG z_${MEb0VuFIkeVTt+kd_nRmCgmhO6Qa^b>trs5rkn?m?T_}Evz+>vT?^?cUvRKt{C zOQY3j=07S~W`o^DW{t+beue}NHjnY*$ z==YcIdT+9PoxJ_lCqMei3qR>^uNP@wmARIs9d?F|9&MEx1$}&x3gQtJmzfpqqGG($ zb|{CV3ds&(tWmNoHaE8pJ#egh`qcHIV$b^@zHsujq`Ot-12sM^Gu#Y0P7u+IgN%(~ zmu9JDJ9!k4g(w?G9r2QY1-j0$BXi#%^0I`YA%K6C2FH~8^wZ)e;T!q>&!pZ?4X zKl)*JYpqQCvdo7mzZ*KaHM1Qa|rRaxe(Be#9&pMK$o-@3LVqCM|>c=_zf zVIioiV!R(xJ2#AXFe`p&N5sc(M8eowE&gp)!xq2=ibSFmwtWnPDagI1_hfJdX3<(GU!WWZ(CRDthRa{KbBv}Li zXTdrZIegC`P>u#s2T<%Y;Vu&J zPBx~~^6_@EH{xWvJ8#-SG1eNbm6GMw#?~E=esJTpcju*jZyh&<@X|Q^_!DQ2zmjw} z%Y2~9!YFCS5;z`m?~HNdxIY!bu_%sD1x&0Q@9=vxo`O$y1i*}mk2jFa3j7}dn1 zEdn!&=m0DLOooVdlopi7&#oW)#3#{E?!DLIMGQ%p++Q~F@m=&Q> z#2;;ZnlXb*k#G?eXmXHZy8NArI5}xHJ)biw4UJY+k++W=E!Nks5f6`k@r%#=&9^!m zt3@)-5ho7fEZE(p&v;RIxWQw(1#~9~@cL8$T>NqR!p(TdI9W8t7_DTHrAv3+eeJph zw|?ZKCtiASu)Q%lHagA`M`MENj2y$*Fc4f6D-hmA$drv8Y4ju_yisy6u98PdGgxbk z)>0;e!NL0;?45mQUs-;Qa8n2`fm=TKp;72BQdL#f$kFU)cng%9TJyLH99s5_iBCNl z&$#_WBWE(fiIu}x0Csx58`W4tOm^Ijb`4l-jWI=@-*W#$-D_atOUI6FuAIvTv#G8g z4}OLb8Ka2`&MXslEqV61b>!Bke&rW``rYqeT`G=!?(;AH$7Xtcd+RM3xqu6Xhh zBRq5me2KK+l2(CXhbYb@hP&&+$%~mDx*NHNtg59u-;=If{Rb8ve&UJc)5nwEc2%TW zmR2ca)G#r!4v?Ga4ZtKC;Nec_(bYMZP7Cmqlbuvd|D{VO2LJ$Qlq6Z0%-Bag167vA zfqU=o-MCFvZ(H0H!reId*kh~bPG$XWIW+E3m&1-{KRa4I7-sWaJiH_ZE@9IXf5ua3 z9EZIbIfSVk!cP01X`KzH}IHM%T{gZE$MbZ_aQhc;Hv=Yw8VW{44W}1XBZWNB%rPf(vv`z+t`#$`Um8;h-{>9(> zXU{zI&Ccd(k@nR%>$i4zc>;h#!>mp}i~_paK*dX9bW>6f2>uHV@x$L)d1rkHV#INJriWGXOikl-CT z!RuKCo=F)ej_`U_(d2}RMGl7Db7zf|)zTezr7Kr+gYn_VA74ImGVOQDJRO}NG8)Wq zpA;a6+>VTSoGVYvV=QlPq=FMRCedT2CPdQ?^6oa$Odn}{my@;5I%A9~%l-G<-#>S~ z_u0M8aZ?C);NYW=uAV=W_B+G$3*FBk%!+appTo z^LEJLZdIHL!qCyj=M2W%sEsa*;+Fd!?47+j>E7al4{okr$dhhWmt zjUVaXuFlUT+oYp#xr>U)9a~dRpB4i<2Ztj*MlvvL4km--z7IcnRkZN)zx!L?_{KN8 zo2z*`P-U)FWwjoUe_*`3butge<9LSvV?1jEc-9y$Nd*}lm)>O+V;W{uaQAc>P4DR( zo5YX`rB*jOpSem}cZlruG1D$i}X;V24Lc z=cqe0V9dh~IUEh!CudehBXy&sT)cW(c<4iquberNj043?XV_iBB&GsCVqkP{+=L34 zeD=Cj>_`)*RP1US>>4HP?4J+ggt4+J_TPP9|GMuve>>x*5KeL1lTWUmKa&l*vdD&; zzQ(;TH}Ugfq#L;$!U&J;dldE1>j=Q462dUCbpSwklIQ~3DTl-NG?s#)6S&FNo6)Be z6&T)E<)oBHAO67B$&+u9iv1t>z~<_OJn6|YH>xs5jV}eB*|9cr=M$PG0gvnB$^92I zY|M;E@nmi~OT}b=&6o<9hP>gQ?AS*$34G(UU~~}E9B zFiN^% zL=mRuaEZEbnix!u=sIxD8m;%e_uj#U^KX%gJ3sM>3#U({gU;{{aii4u)@*RI?a)bT z2xA6@RN&W17V#ygDsN21C}~EsZZctK3OBJ92i94qv^xCYvCipt=QB{R05^qjga>~9 zsWT^DO?um->$CMZ^t<6^&KU*Tp>PCGEEvx!BAMiXc&1()*8zCa<=Jts*hKcwq#3$n zYB;`+c!bHeIha;OwkqYlPdu^m$}3k)#nF#Exq9|=Ht5PS)3TbJjT?@^&~)s95scP2 ztA(@Cf6N93L}o<-X8nH`6)=V3(2U`Bymnx$P15|=zx<2Oe*4OYWcwd} z|JK@tJn5?{*J^xW^sEXF%i>Y4vx5g1voTi!@y`GNAOJ~3K~xsM(Q6o+2in~k8;=QL zmI^#IipkEZi=*C-y~b`_35=}5XtVddcMsmeVY1)(?|=In-+Z>WwO(Y2stT(nQ*$@^ zzq=g{0wa?kFe!lW#WFDRpx2=SPuDu_7z6B18DY0W%ybXXbldf)J*bsBeC+*iWoOw# zpZ$f?ufCe}w#$4pI&oGzH))bjbEC0gkIe&L!a?vX31f}!2XDUK8(;7OohSX`i-tp!FS+rRjn*1_b}LC&uJB;>t&cyxdf`kq=#3Ks<*Wv0 zM+f6zyjytM$eoSvqZo&$Y>-Q^aWNGzL&ff&{bX7=6AE{dFmA^UheK#GFf&@+^1wsg zGgml5K3AIU^_4vB56j|78_?}4i+5#3lR{@o0va2}MQ(Bt72{jg@H91?9hT4Ljx%O4 zNvfue!4XE?b0w?yeDFhSufBE#Jp9~me)+i{|76hFD6&M$!b~5rISmx!srl^CWYRYp zImjp*7+T2CFlOCnO2vr5iBs$d6w_Q_(m|PaYGA_E%wDVMN*q{gi{k2ZP2L5#DTDw3 z1tGnyjWVD1d`7k4B;HNV2A~-e$CI89nRW$-4-y()k2y_*hYwd9*Midq$YcY+wBb2h z7|j^;1k=AZt&xT%jz%S-bFQBh+3K4XfTw@wH=g_P^ZjW;FjB$Ugy7;$kFe8+XLuMf zFl1vk$=yN4xDv`ZSN8wYppBtql*c<0E(S$pV#2Rm!!o6tmMr~FJOr{g~!QL)2L z+@yvY{%xbpmCa3Wef;r_mGgPhlhtrqtgRaj!=?u%(Tr=rxayrL1Vdtrn8it)#3O%$6pw6>6|NyDqVf6 zZS!{lZVDkB{?KDvtII{wmsLJI6g)f`4Q_f#7`nK{F-h_8BtDyj7q@dUz#+F9Jni(0Sp}KZmbpAK*|4~y*GQdZN2Wo#u(o> zo7L>S&pzk&jU;T48-$G;45qWOgdGExZ7j>OO++j?gc2rIRH#((52W%=RUVR}LU;%i zsZ{Zhs=NTHA`szD$nw>du5aI+dz#&@W;S0lMjpOqesi58TQ0C9>oD)Bb=O{d?X~6{ zbF{zFCHPBHllTP1L`?^Wsy|6P#UoBe&L*&Mb+f07xh$g4c;$tZWGD^59gXeo-ur#g;RiqdGq1n$a;gf6lLdjLoE=yaA_Kw& zS!ObVM2Zw*6c#Kcr6fpMLpI&;3>6e5p0E-(vI>H}C%b3TOVpeu|{onm3FW-FB3uhj6L-?mZ_S3=fH^V-xjG0QmU}|GJKIA%FA(8R__Oxe!=76$1DVsCs<&Kk@KaDCcO9G|KSh6{Z$))@BGn^+_SxtfaFtYhRK{(U?50{Z_7geAPCSuG;L6h=7@C>Hh!Tidn$I>&L0%km57=ds5(|`KjD_?C{ z*`NLR&%FN1%e$+PG8p4}#i%HX{OAniD1D<@luV^vR7q+cLJBGhXeRkD6NDu?kh3jw z&tM9fvG~(WRA&C3ANi4YUi@0jqWgwD9(6;Nc&_nP<_aubr9hb&Fw@L8n&hNN8E2m$-{Ki;j^*v2 z?8Ou}Wl=#uV3r^K*iU@<*T1R>oVKp79_|oC+-M4m;ZR1Rzc_)S>OmP%O5uZ~m`O<% zmIE=FGRfsNXG58|st_R*n17(PU#+6}W<4HhL-?J4`NQ{azte56?bHdxB^-K?|1XtY zsrQ3LM5U72BO*-{epX7U1bP%s8J7C41oiT>(wU6`UlAjf%JIN0gtA8Ct8{x!yF9;l zr{8bGH0`iW0`km`aQV{&(ZV6f8Xrr~AU=r{AXU;PnTmoG4-xNtWo7I;y_(|2A|lGl zuF(FmWq}9~|NLM1vDZHTd+)B2)$;1%Z0tjqv<a7_k#&6RlicCg1*z0)+)RIF$10?C#RVTV~~zn zDDVI-Hs#P}Q9_X#zzJSrfxrF>Klz1!|GD3V6o2vOKlbKpukAONVW4)bm@WE(3#jf; z*-;S%rUYTocVT&UpoR{InnQw6NceO`34M$qFT(uNOTcupmC34>S`U(4iFeRAzIyxj zXd(E}kACFd?RUD}wHbSt$|H-;u<$k0$QYPux=fQ;AUdfzrHDu?rATR|b){8-j-?hc zm{EEnMBxG?A{2-L&Y7gNf(2R(2ob0wMEbTL_<`TkJ@U)N<=MS{7b?gs$3;Ro0|_Pr zP~hYx7%-*86p|u!C?l1sqQjVYV{(WJ(a8K!+;}K%e?b~JBv)oH0KgOs1z`rnANbLa zy!qQ-{9Wkq$-novKL3RmH<#yQw=aAn2x}jT8}^`kG^-@YGBSCJi5S5rsB|PnBHa|e z!sG`OvYy@G2Uy_1S$6{rRW{#%$D?Zq_jP-AFEmQ0 z7$_w_CjV|q5EhU{gnFibv1Nj?bStfOrFB!+m9BJ>bD8;VCCU|FfCr_09w8OMA5M^0 zk^jiX6_ZLvR67G_um5gkle}79o!uL{osAndQfqLrL@Co@a&;%|uPD)hVl*5qq0-3& zwsl=qb+(1EdST|_&s_X6)+tN`JRs-z0Qt%^iKKen2+V%phyT)BU;K)>kpKGc{?g}O z{GH9!`H(6_lgfkKJvq%onCUxJC_A01gi?j1QWSgvrM1>oRkd}al~SaGx{Fh z_ZMg9hzDFS1IP{yKp7N8vzY8I{^G~~>Tmw)S8TBPb07cdx8HbkzqvGV+i(O$=Ye23 z9ij+}4{4$&)FkqS(n?jjsiz%Bo#lZ(mGIa^!oDS3dKL{TYAv9)A zs3SVh*YEspRWrkKeRk(|zYinjB5sst4i^pq;sfDeP79|>az#@PB|3^(Mw+_TT31R3 zHkx2fpzPITn>WRS2T6j&0R>zj1sNwOA&0TKG-=bj^EV#Rs+mXB5PtkuKK0T|uY^31 zv!l#FQOe6=W_o|t^g5ZqYy*@co!Gjrs%6_O7mLNBt#nmu?Krg_XBhAhI4umyeVj0A%)yf`>|GJ}VN$k$MR6O<=u`rOvz$;#)+vb1 z1u9AquipNO!0HzQDi@-bD!FYSNqVK)(6`?S7d~|hw z)_1#NxP;`c`2fF9>{00bS&k5c70f1(bcD%+-mluaSudAOU2CN)tv$cW$CAGGp)gWuA?Lng4iYEZ zSOV46U;Wvi_~KVk6yMy(BWeiYvEbiT zx>~gD@pApXr=NNH>E~~*m-}G=5YG~~6imZEpg^>e8qC~_SQ@-S&I`mW2ZIF)2!$aG zvSvl!{R&#IzIo&F?EbJ%6ScrQWJ!Eq=`2<1GmDYde$3Fb}7ak6U z)u$)htBbMk;yfMpsdpY2tMqyE^v~?_rx^mVLL|imN~ucgx~`V(;_=fP-}2n^r#Ei; zn0<`QH*<)xr7M)#bh&s)sWRzY;LN4|&o(P)J*{-LdH3O&!XNp?pMCqyw|1LrGxW}d z$|;6f?);$YYt|n3Fn&ldDXB<`s&1R+WW9dk*5mJg_Wf<8M{5Lx8F(T^>IsB6UJ$cI zE5gKCO5ngu7QW;ZUxqvf5n?pUNY%wx$Q0t~>Dk>o-F_F!g~U4vo=bt2!{jC&a>WA$ zGC491w?S*ID_u2BbF^GOar4%bPdsz;=%_b_Fw6_jm!HmOX6`1x>_HjHu4O48h1jIC zkEa=3SSRZ4tB>N`wMWztRyU5f*Oz0zcX@iGAObMxV*c5K`mQK@$wHn)9g$)TRM(5P zdF)2U5rJpDXFzmj&CCj?7$6bk)R zRI6-mKcp(`Cw}=CUw!5E-R9a1U78*lw~DiBivTEHbm)nGm=%n8V5$sKDI8oh&B=QG zC%*kd|KJ~d4D}zs_wLKPZf`xu^+^ZElprj@(E}6^;9&+}9!6xxAi>pprywio5qRue;aHnK4ep7|#L#*JONvMFuh$v)$+PYaU79V)_`Ty~M_~jq{ z$oGBzb8qc-TkD;Vi-Tg{hs-Xt#P$kMxTL`>D9j;X)_R4>ip(1Wfbaf`fBu~>J!HU2 zee3l6{@nnTv$O0cgrH&LshXw4W?l1TFjRET#N;t%XR)rTW!pY+>+!$+OaJZP_#5B* z+RInhR~MtPE-p8gxkMyz4`+A!VQKX#RGb2$iFlcz1(Sb7q_k2$^3flE>2nVmuu|PP z+FV|YeHVuhXNN$ray?UxsqAa&1|>y=_&|f;ysb7lsY=&XwP>5um7u6w2si(2QLs1d=6@RiqI{1^Y?jo*6lg~P z?_6Ib6gsAJ5Rndy&}8MJUptFYX0-zl);6;9&RR2WuP%S_SAOY1Qry3H-wb`8D}?Fv z*3eC{B@`y`uuClAV~HFofKCPUNk=QffBMgU`+xo4K7V#~F<5IovjFFtn49R5F~!3% zt!0VkJbhaz$O(cEwJm}I(}E^%?Kt%J?>(fs{ulo4FKw=_tQnoP%$`}|I$%TqG-@#$ z7D#h~Ok|nLwNjlJmPMg4VTtf>f9>D=>wk6m#(VE|#v1k>>(- zEDX$i_v&i<#V>r}%P;i9updV6IaXajVGA>~0vx_HJ_P_wuKk}36g1Y#sh#_ zK9Z=jXXnf~Y_6{#eADLo+Kyvt80X}RV-HKjuu!d(^GOtoKKi7gCS5!&9TX%1-1hzJ zZ@u~UoquA?I1YnxK9`;YV#wtSA_@W_2njQUIE;W87#IZsQKH|*2qeImF1~=zrg@5j z$;%UjxW3(cYlgmi<()&H_pg2G6Tk5rzvZmqxPCdQW55oNLeO4zZ6-!2ha*g?xmdV5 z{XQt5(b(5-zk9j4Hly7ReQz!2uz1qrlo}LB0Du?-fdd2=7=lqyLhd#q3nD-WEYsMK z06XV>6bJ$+0K$@1miN2uU;Feg{9pg*e=kY#@|(AZq4U-XJ77j&fkbI649Ou^6t=&- zayl^BDIx>#%=a#@_MiXt|M1(N+xOjm7(Gi7{Scr45|R*yThFnzmw=f85GauaBEv`& zp2P!5-VTuWw6Mi9d+(hchwb&%L#4xvLz*nXAd(ylSisQZvVd??>1-YdknLQ_D+M*O z6%+(!*>v3tzw@Opz5ePr_QNokRG12>=&OJ@C`{4~#m0dJfB}I4P+|qL0C4)9fN%z( zW(mW*%Q-sD){gzf#l^!l$~X1#$VG&o_{=AVZXZ=1Gemq2fiz6uNfG!wudnyrXsr)xq9LQ2la$Ott68eAsLz}?oMDop^a*)%^{lcYT0(D~ z8TZ@mCqDDZk`#aG6F)ih0TE5%VCa{yeUYNfpHJDfSJAb-rBLhd_dISy>o9I z`aC@{PYgNIzNEt;T0Yr;d~)TR^BDyf0gUsbvzNQw?X&YcSC?1&z4Po@IH~`l&zW*Y z2WB)$Ps=L%Jea1qL1|m^6c2@fG;b<&&WuC<-krms@ap2y4nvB8I2UG4naWulHWQ6` zv|0phbN4|2J)n2|mO1)j@vBleGy6^`xg|psxn*S@E0;mx1m`B; zB#^>8XYJ5;AO3}(F6r=dpZVl&yLD#tv3!gRi~$E+mOOcI?Wvm(ACTDsqD`e|A}~5P z7;}Dob^rYAYP;L@gZIpZH#S`YO-zs}QAVZZkv;WNOs1eYpGb6%y!Xyo)9?2`|9Af8 ze^RCUhv0bRBEr|-y*muO&s&y&F)wpKijFoG5#ijWJveekCQBNNfUxtxEY7n4GXpa- zvj7wY=*g{)_#qZ8hA0xE%jm!%k}v}jFhdbDLXH3+y)Y}814x@{y|ZTM-*|VX_0G>P z?Kp(psxcf4M!H^wbDLu_n310YT9gh%k%mE*aDpP@Vn8h715TOqgQ>c^h{dODDCA;# zLSO=5#4y>5fe3^FK!DP+g&YlHp0bvS5e$HL-dWRk`=9^JC;#dH^iMJ=wwsMLBgb{S zl0RwZs~EG!Yn;6PnI43LS71W-!hHbXKn^F$v$bA;nZw%fkSq;_fB{I(mmirTmK2F# zj>!NLCs4X}o&ugCR-Up%kj_O!*t2uijJwUIWQk9F=9B;S-~XnwHZ=)MV4wg5p@?*y zr%NG$*rmrX6}C*yN;Jlv82~(s^)X%SIpz)|!MOpGNK<)ZQTLSUlGqC&Odt#h0E7f0 zEP+*E+QBjL1wdSADS1Unh=hjo^O<|}#yfY+kcx+yCz>Ll*+YFKa~Xlj4@uq-AQWcs zKt{q%VF6$cm*+f%`{N>O$dpM5>(3BT!Xmbb4W=TZ3<=EG;{m`Zm0~B=lU@xA?42El z?#*`}xisM;7ZF}vUb=AzU|`Usldct>d9IY&dtt)*rrMN=zab|<0wBdAp2ag;@2z9U z-ZOj2NwHZG-+{YZq{3q@>O9nvV%U?9jjY-sBT}^p`$9be(e(E?R~T2T^;D{fbay!c6CZWARP^2Js@^i}P%pw~k$; z#*`H+D|}`=HeFPvMfr8{i^}K=4o)WXt)xsL`;Z>{=%;@!lj6;H?~KC`_b>xbWxet9 zA;SX)M3~5x2~vi!1q%yck`eaI#yRV}^*-i}Gh?Ls&f-I`pm}k1G`sc(GM5h$YD&xH z_}H3pzulJ7u?fDBb0Qou#K;c>_0bIdm@f716hHN;kDK5SBvOR09|QG8FhwEVMvb%N@35GBTGM(P7Y9 zqM9)th*+^3$E&N!J=*X0&YILUD7jo!4Od0ca!KL&&6%G``C|6n!oo-qU;&9PqhuLL zKEc!mlKsw!B-uMD@Ae$CorP$GR8*Wzfh!9dV{R0R7K28<*vj&UA>QVe>q3YZuf(VFbcHWw+t5_Y^ zb$cIte`gT*>YXp{@4ZaJH6ozdmP(_z=J>ri^q5~m3%)z<6$5^*W{Bokk4ge(4v)lW;9CwAjQWK6pT2*$A0!VA&VCl4_DL=a=*nE{-tI5KBVlgf%a|9~Yb zo!4pTTjGnEQJ4~IAPgXRXLtYrAOJ~3K~xbZuzerhqsyzSTt*O@=XuNC8xq z<}#Bd7JoB^;*VS$PYBGZPzZqpIcN@%SZa@9MTBGm$GId4#EkW$QR_K#ad`y*AOGc_ z``mATG2o(`cRt@VYh#T@E&KbpdJ>#Ly}*(h^8hHT>H|YXp{c9rlPNAWx6n+*Fw@P8 zMed>7fnq$(0K}NO2oNKOhzJOSP+}++oJA55^e)h~9Y&YnLIa?q5o&BU0HgRn^&i>?nrARq}@ z{E0CrRF{P7OIf!6Henm!t{8SvtzpMBv6yK5B*`eDu)Afm0yDW{*JIvo{bl zkzYRXT{+bcnChn{&vPhO4`aC%#P}jnjN+yV%?Wmj6q(GYeL!_$2N-2`U>Y76}Rmr5%R%qJS_m z5rqn}DBD;FIU$H32QdH<1PaCQIMe9Oz@Z;k0T0KBMISG#Lw00!+x zGxoH&1p+`59kTY%NwQhA52g<0=m`ERO`VDa9V5dgZrXYYg^0*j}s%L_y#)u`2Dr>(yj7d-B$ zIi7c{)7&SR>-&N_vCJ}=jRbN<*9cRex&)htnK3AhAmY?Y80}r414!f$fb1AW{g}Lg zh_y|=QKANw)BpzY>@;0xG@EbOk5OWWqE?a6*8HO=N?W^XkH(1Fr4k6N{Aw)Sf6 z8MMTTpmu8)iIv!tAXOtRRj>D)_dVzN@O*f_Jm=i^bzk@OThAUHUuh!feoIH~wcNDp zj{Mkp)O?>+86Y;}&RsKx^KqfcEv7zNWyuvxD;&>(W-~Gxu>((y(zI^x8!;xxsD4*g zqjdggpIXqE${xERRiW8ADa;eq+e2s?0_rCnDOKyAYqM}P^|--zh8}hH`*FQZ4GukyRQRuaC0;56P4xERI#y{dG=+MDNm33nuyKq+hTP3JP$!K zXVj~G#@;cCD5mWwdv(E#x|2C&H*Ek{Y!L=?xpl)L6+?OsWq_eyfL$Z9C@FxXVJ-y&=9HTDKjg*#;$w;F36klP_Xqd_ElRf!h>=!|!@!)Y&K;n6VImWLg@fev3@G zR8$TdU?4F4%>(7D>B{WHUxCZtm&fD4kW)@IL}A@Teaql|^(BNta*zQI2{%0c<+94D z5(9j%Bw>%I8Wiysi*zghLDreqaG}uU2&A~PqA?f`D`9^hB@^WYmi15?7>bICalq-T zrgF_SHQ9+H|1x>0s4Mk;xZF&A>yuCP>Ll|t*1%sa4tA_o4@DfPUpLDf z-JjjZa66UB#td_5=E}@aII$}g^q5RPFnFEm(ebS`|N1p%ol0->e0oDcVg1w~Kagh% zaHyCT;HG_eu!fO>)-U_s{OD`LB8c^B?RNC{f6f0e?!5LFXN)s_uJ~5nJMw>q(-xV! zmupAT=j=ZJHMEsT805y#nW zlC?ozaho;M)KUMAN*HGS(Nk4wusUn)Q{K_ZzP$Lih6o@B z4{L?4U({5-cxTJXNHy1)=Sz)=@c$}Bz@z+B4#2OC%{QM`4DP6W;x4@qVy9HwP@f?? z;SvH~Z_JbZE{eEW=aUYqhp_JWWB=7c4L+}`Eg6^CytNriL3s zEVtiKI-9d+?gyC+3LfSj>kbO&iFBShak7A=QN9e&7~y~dX$sNO%! zKNs{O>Xg>M6`?|hAcj@tIo13=oX$W0G8K4ZZv8|r8+{YJKS3})xnc*d-|5nV8k`=y z0G@%J*r9AqNFhaNa+L6W)nD6G>;>F?vZXOzZIn@b4G)s25`BSQUSeursYSN#8L5E* zks#?t+LVWptu%9zi%z?wFi|anfh&pP-qgXNgB74r^GRP%3ot?nhI%|xFohiwsbmKsfAZ`!rpJB z<8P1#i_KsOts?&h$H-q#PiHHR81tT%uOwKflKXn1vc>`rH)oSsUQH}}W~r&}>>jtX zRJ+JG%s?QH%2h7%AMPKcrL}8hKa`!P$=r^L;j)By2oDOzOS$OZa;7aG*5o7$zNDiB zv&MWB+4Db2D^6Oj8xndB#K`*lv^+iCw=tqG2$)#D9|iZq%u8{iUMyozPP#NAYNo~$ z;*~>=7_M4^fy1V;ou&ZW%P4tem+-TTWjrDD{`kjnc`xT%`idnh<=Cp2t-ctGo&qbX zg6O0w>Nm3C@k(Jd6eo0|y~oBIv@e`%fNIMWk!jMp(g1?B_+C5ORy9ukij*%9x?5o} zJ5b@4-{H<{I=ku5`)xB%TWPzVgt>3q?dN@_A9D70j&y*zh=L?*PJ|N47Gi!+O-yd( zeo)Poev`m+T}`mMF+tElD^8l;QJ9jpJnbuF$HQse1zXbe`rW%L{vNGqgmfSaUi z%U}Dcm695HB^0g;;FoG>aW_-&8`HHT(W(Q|JCK9LKK@)SUq+mX?qmCuJKKRYuYF|3w0s| zBUu0GN`Qrv_U5etsxE{gJp8$=qUKB9;H}?tQTMwSklD#6{wT{=XbSu19_f=I9%Baw z;@$p7&rzKx$lx&I6-egPy@RghRrnD0_YX_8<#V3zW893Rj#1Y{9mA#zWU2rO32FWIll_4w${ofqea zzk;nT@&+2RB>~Kftpn$}(Jy`y@UJg?YMsN@4?Sid8%d)V8~)yh#Q$aq-DYuvo;|Tk zka3(!du|$`PkGmgF`-5IE{%Hie~Q)do%`C3dbpX90Tx|Gz;M zez3;x174{U90@A%R$G}kG*z{Z4Gi&ZW>+is#WC%@vC4uP^y|bVQF?}*82VitY@Ou+ zvTJ!Q$hK&&v){E+;itLV4+BGq^NQm4x4wTAnF9<*w1mi})cQEL zo5^;|L7CeKGb{tj(_IHBT7Qunm6W&%$Pk72ju$P51ib!(F!1f#r&hB(9qbP9I+?e!hAntIzmF%>7cWpR$swmi;ie2j^3|<(>KAFKhl`X{o?Tnxr*2I^len$ z-K1pQP^C}Z>ub(8y8L$M^^rn23f8$jvDO&G9i%T>KNYM0QS>>mRtIx06gXlWxW7 zXO*lZKK1uq0Xr-yQi(+ErE}*FD4&j731MH6FkuTdg*2*96R9;>XQ55D_XY!z$0shz z!P_^b7CYci#U8#HIdAB>ut0YyV1?G;eoHn>2;5L@X+FD#BeSErvoVd5rxcgQyC&ZH z)3jTb-d}q9LTTvku**~=+@gL?cu?>|I=%O;&)$+i&fR~p%2z8a@ceXSu{Oj=BAc|N zT)SA~y4xjCPd?3kQA8k-i;C+{;O%>7T?*Roe+{P9&`eNv?hHxyHj)$=s_jBn?GDhZ z$ri6Kly8jq2ZdhcUwz$~)^$tk`SJ8y&}ypgx9t}qNoJpDw}TTTPI`+$f)9;IUn^wq zN3z=zCD9S#`V*F$mPIyeT|J*(%ahZGbL%0GB6Av<~YnH-Tc?lP{vyANX9KlWx=iqj@g zYU#5s(oz^laOd38?>!;#tPhPJqdTxGd;sg(|GucSyb7+nN*<{He)i)f^2y2iTx#iU zN4GRFh7}BN(&lgnHsw5^`|o9uN6TBSi=nQ4THH`;C#nMxhiJ9rcPe6$opSt@Mv3G1 z94L^vO_#8~M#&=Wlfi8GkZrq!=PR>XB7;+U3Q(FMBwi!(filhpFSN|m!bU9c=~I1S z?|}_ow<>099PDU8rq&2;@7a&eaXZ*SnFOiW0I7qqB(69-Ccu`jfFh#w6x^9vm*UhLWZIAKyvU*k#l!g=zwF!hHX*8Oa(!3f*+y zGYm_-yV1L;pj!0jsmR51(>bMv=8~Drx1tZYW2j@^41|!owlDh!7Cr7u!K$Z%oc?~E z9c{eX;XM5x=UH%*O+!|+SElLcBsLio6g%d^GQ6gS`)1YP=00b=?S@=NU;H}#dsCgK z(CH`X^<`YvP-^R2zn2WuPhDHG8UaJxrb^c!Ph!EYt*-{7I(?o^W?cYsMh9Qrjf>fF zSi?M4*K+6xVs2HGgo0S_^(pSv? z^jrmAXyU`D4w2ry{!n{C(>W-%ld^1*iE-FCOsPqHSM#hxheWY^0U@FWSvLdpo8x?6IJKm z?=P~UeT?X0JE;Zo>k%?wXZCQ6+bKry){>G4w@`?Bq;iQynpmTf5z(+Poh3b;QHti_ zX96zswnRH*k=12_fNmuOAGX!^woT}|k+`2Ir6)ED&?1Rr^-dnCPap6!7|SO+lGMaW zcm(cK;Grsg?i;z!jpS!La5Or2^UWnKpz!G2EA$}u(XWjr0lp!GUubO-{dK1p;P2I> zFMApkUNr_RyAbA=dI+zqbj|BI!ncycj%ER1}8xV3Y@`)WBtv>P6u;t{waP)(Ru(&_ubG)saBwyZXT6~Q2-c475L0VFr zi5ooQp>6Ah=f$t=OC;|D*1)Xw=@&H9g({~MP|2u|12d{L-X$%G3jz=jTlwAbrg&E2 z{{PnYZdMji#Vp<9$Y!u!hczb&18kwN(ibzX)#@*c@UO-JRrNYRU#-5C#euU|tri_S zV^vSb1WWx0=M|=pi5&3-cD7gDn8gB@wX364qUT&HjHpZWq`4YqYC72zV_u)%x+ILO zQJ8428zCN|@I?hHniG8DU#I_B z0Vr5B`9W5i@xI9P;&)4}02mQ}(24D+se>7qG-MxFdjN`kv$^JdEZTR6R&+C7Lk@2IcukSHC{2^P))O6IA zij=V|4oS}!%p#5R8bQ1|rW1i*xe~HfzjwLDP6k#*V6>0O+PTE&YftJ$}KP}tX+Aga+pbN`Cw`o8{HOgMU##I<_BilmL5(=YE zk{`8Yl~~kH?>sqs9bZcOKsjr63hA));NRbXxbQ{Ms|gfIK7>|B+9}C1S0*;s-hWs^ zi2lo+ztb8&`kbyoAmd)Qgakig`Nioc^?odaReQquaES}LvZAINg;bnZfHnV<6OAhw zwss|PYTgU=j57Lm$HFtBu7ckzOC1M25d6sxipQe-#$63C0-#29rr|{*xn3b4c{T63 zZ|M5*SDV(LwTstx^S5c`Xr#{@@e;9T^F7gJA_0y`g3J<00QxU7+k&#E42hO2+S=gf z<=4aud##K1TVzRRDe^@R{Td zg_M+L?BkI)GK0}Ee>lfSx&p2^kp(9)(rYU>*-WkFlUnMrD`Sml(!huA^J^aSjZhth zqQ6e~EytiU-xY023hFJ()-6R5i6_W@(fw-xE*0mGkoRmqEhZ=_=?4--(s*nPdTsAv zpim@A2tN7#R(&VSVKk&8?0kedkk1BP)j&EK&v9BaKnq6ghbum)A?k8_EL8B&i1!*y z^Eco$n{9UyKLB5nXwt=Of=F`ek04kUvprJCQm^p^(GW z-Ap`r?@O><(+d~XI%3DN`+~Fk}EvQbIBRV!F^-nK@rAQL~=C6O3SRv&$@C~)-s*~ccS@Zx~-UR-@j4W<)8~(|67j79}y}i zUp_6~Bj$fOtM>g`d@}RcKuXCW<3%=Q3%NGleQ6^cI!@iwNz8EK zba@UIgurV%Y$WV`F+Sse!nx#Ekrmzscrqsir~825I2vw3)*y9C+!)y`f$EBv*CeX1 zq(qg;g}l(FQ8npYghBi|ZzGBBkFc5b8Gw7R^YDOWtAOpl{x0Tn=A?i7E20&Q#m${GUT#=?J=^%Nq^7j0F0Mb*s)S{-QhM?GID)bRv z00813y{`(K9Ljwkof4gWG<~A42MNSBB~kU50eXEkn!NM9g$mz}49xx%mFe33c=Q{w|Ev@h=e1JovGf z=jm)!ZA!K~-mcTu0`9Y&VwyP6kjIhMweZS9p@`AMX-;T>uM(IL4>^`-|7&?2l6WEk z%DX)fGUSDcQxMdxMyyPoJDVvx&;kghKp#sbaVV6<9Pt1f9MMX$gQ%ikO`yYUTJI)3 z_H&}9Lj_PJH0*xM@tUgZM3sC^5n`}>pQ$-%{&iwJG#0ZprotuKZgs>| zi)5z?-Pwo^?2Yq_sn7Ti7}%_D7@`?#`_}~R|B-Cdsu<1~(JPl&efL3d@{h2dT51Zp z;u~HP^y|Y9uI&v7#rtUI!GHe9J_skiY8Sg{*B*du8t?fp=`8@3T=*vP6;npKg84PTi z9{c1~iZ!5*&AA3p10Qs}t+3^Z)fGQv24Nx~9SbbFR;o2(*Lq^?2fJXBNb+!}YNLd1 z^_bRcU*d3}hqgGtus>-S=}6(R|JlYLKdv~H7XjyVLn2M;$hxj|nJ5>oLesfi2NXQ^ zOACsy-}2V~>nJ_E28D9U(KC}zzUf}te1mXY_#N1vz38TDFGXo=k%_vPhe`nqpz{|Y z1ZAYyV+Q5DR9q$c;8|;>vd7iNj)k~n5ta;n@F~R!n5!_CHhM=H zS!>Wb+i`Pg*ib^5x{a$rXSKxjdD}9t85CCbE2;AFP<|H`z%(wx}02MuiQBQt(Q(G-n1r>F(!E}`CUr3 z3LP@ofM`}h$oCEi8!>3U1!rU72JgJhdWR7>j-Jd)j3J(Q4~#;_??W~pSTs)}lU%5u z=K20eL1vr|=OY;62_uLIU2&3@X0v(UTyo2uGF`W2yn{>GHwPhz&O)+92WGYN*7vJ~ zb-+3X1diucFu*Y9Y7E(G!jU=7(4ncHy!| z+>lYKIMhP7^H6@35NQ7iD+YBfrx>_j+u0a@8)`8oeM*1Le1dnKYy;g z4jznl+4}6E%j@bIj;)j@34W@4QJSaN^Ty=`Ix1B&(PYod;OdG`Y!^{P;U!%A;`;L8ViMmkW?FyVrqP?S(7rd zz+hV4QdFJ%L0nh8n1OIl={$15AB}0MS|s>N2vO1>W4Pr+PbqOxXytaR4w6ee$q)3{lTyzAi>l?0TcM$aaCyDz;&{GI;1cJJZ``I*YFzGpoG1 z5FcRzKFi||Yxt2z9jAOuq;^k?ca^`N;auhvd)AR-K(`tKY~W;JYgQ05|l zq-2CnAAzekjaS3}u43P)?sWj;tCU6anqX5i{DAy|q(vU9t`+~ruCo3*+M zzF6VDD{Y-RaL>=F4qB%2)?By$?PCKbXxlQ2E-S6|E;!H?_TJf}&`yB~?6+=MO9-+f z4k`;>Sj`!a?TKu7$y=3yPCWd#Yd1}*qN~}#J@&6W3OVcK-)O}+baI-!@^#H`am^-{ zq6FMM;%Z!dkpkB1gGmb}9&d6P(dDLN@F(N1Bm>6(<1wXA7gOhoRV%m#6b<*nx-p4- zr0~EivaXiSM#a-Ob@u5>#q2w_ADrJoK^!2mV-89Jas}x!Y&$i8rU0Bd5566JM1Tf0{ z>R@^Oe>k1-%CvQ=6cMhFqFa07=;hOXf0=pk&!#%n>Uc0G7`dp+s_gbgXMT!)(mr-d zk+Ytdm$slA;zIpvZC=@l3Ebj0khK2t%F-`HOB1Xoxxw@{bF;*GqIczHoIQ|YzBm8^ zNSx^sm>)T*7cyN$RA$y>&^QqFks0RSLfEsq6d>_WmF{fk6ZgXx$>+uvQ{1KUSROFv zT>qz$Ps8ds#?RQ@Pgg<3KUprv)}gYB0nLaHLA#%6xV)5XJvS}tf9kxD!|I1(_1a%wT&My4@_`T-Xmz!Q8|QP`6)j zX(!7Lo zZ&&F0Wv!g%qq(rUtWolWBy1Clvy=bx7vGbWuXm!})Y+>D1(Yvw%& z-i`}DwvA{89>iUAEy^f^8pl(y;_3Zv+FTU1gw;`9)|z*WON=JFzs9#JU4 z{iL{qz{1#p6hDrFx+52rD<`GoT58xn9$elb;lt||>y?YW^0WQsLo8+kloS>d3Vl1S z^N1ql@IRwq@nxCKFX>|Xsep7bfvW;59%|}WZ^lBxs!Ua^las|71&S%}4GR=ooQ58f zNuhSL^%xxN=$;doI!(QnefsfmlD*ZUY!Xc+pxv9Vy~hD}9*g9(Q8QPDd10xCer!5AZ<=K@J7pIv}i z+$zC_SjaaOI9kY(KcgzN`_CsnXNFa?2v%?aa)!SohzvxiT34&7TQHe4D?{!&DioR) znU2d;@i0s%U3YTL=N3%QYj9IaidF_Je10lDi8=9AXhKi7Wf8{wZL%+|o6@IHdZQ5V zU{2iX&e#}w`Sl?~_s@W=II&Wa}04K7OV?{zohgbwqiK;9&=1RNp=#eQ8Dx*lrC3$4++4F2oG@wq9Rg zNsnXa`l*6d_`EUC2M|ai50A9s~_WDOyeh06-LaPmbTn!Xp{{$5O<&lzIKU2bN z-HhW(2#y3;kbh(EVv{ebD9D<*FjiMhrApr`fqEtJskVHWxyVQQ2rGZB8pEPt{03t| z6A{GqZaAle>aJNz0x;hlF*lpj=z7C(b>-vs5QoWM`LEQlTBmWh>a8M(Y;S!+V*FOt zFD`Yip`E~-e{q+muP;q-dyl$*Gy25b=%PRBL4=?{tg&t&aqMTX7WpKzeLluB`O~!9>u3v*dFY%v#hB zpCvld0S%T6*nO0i;p;j5ITSwJ+Yk8p;bQ1DDSG6hU>dYe9j?<(Zkf>1=P+=SOz;w4 zM2SjwD?YkcwbEiI4tQuVKMJUtaj8ihgy~Ho%-`EXY0{0E*9pV7$ng= zzr8Z8Lo6a2`6VUAS6SbOggNb+8Pur{cE$OLA3)wUTZuvq^3PQ^D&zX5r&kq?^m~&q zWYgV0!Q8U@W<_B}rwfjQ_%9*&(-s}|co|C7Z+)b0G9o1^g4HwW8J5FX-<`hE$}U^H z)E#M}57srKqLe?MK}6?{on}#zDHRyOo>fR}egC1Hi>7_QpZM-`8hB00%0ExZ_^1ej zS^Nl=j&(BHIMKm_vc5bUR+$DFSqO0}pD~47TU-M;77ecM?EI9q``i0|`fz9GC6-?b zM>rqaK5}(&(Nsm*T322ntR?yI#jr2&qD(@7GP&^ei-2oW9cJ-K592N@#tHoYrBbYo zsR)`dep2>(W5mzzR(rtj^xP!^_ikB<2~%4wW5TFrphq;gN#O*P(bTl9PeqZva{O5; z7X0RGY6d_75p^|`d1zLrm53N?BK}J-?KG0u0^L8LAuhO0V}0{tw_As#y1d96($_dC z8&ID-=f!+#G1t^&H9XHE&sW`U-vY4teZ2hp=uZQn=TpN1onT{9oDu_MZq-xz<%-SZ zq}TJjH^E0V`lHzkx+F{hgv~`0v_;6s(Q{uI<3ku#W|+Df;BS?Q(yAwdyMhCK({4`T znPx)g^Qa*9t~UYL@_ic#A!el$0>zKd@_?W9kj^Z}!l!87;{)VLpNf%EXOPd?8m|$8 zMV6u>1FtrFQ#X-~(tq}%@Q|u~3b$t~y!)XXIsf7SQl@`%W%lC4Q<0B0mnue(rTjV< zB>m4A$VNF1q^{G~=#FVEGV_%+ZmQ6qK~dNnM%R#SpQ!6509vrA(;%l%Z?arv=N-)pP(!V36;LMRskp z4v0N8*eBRKL<497Nmo&3a?)0x01KWXPH5TC%oK!~M!{ zXFF`Z`Ga!f*nv}f2)+teMgGbztNHsBciAZG^*FK$s3@6&L{PJ^9Hnx7ppE>S#_Z_z z(7R4RSLz(h z?sb}LQLm|d%UEx^V?^bX(a+{l0lGFCs=qclYgb9BW+D!eiQDm|1zeuI{`2VJlGHY8 zTuID_jmI<|Txb2~_h&+xV)FF+pbp-5t%KkL{z%*i&DQ8IDyT``V1e1FjLaJw9!%{Z z=*^**mEknk^v{h0g!tm0U=BxzdqXmJ)OHOF{O)Wt6TX1sH*#REfIO$J-0h>5t0Bz- zD&tAhJL;4}U2bP#arES<5VU=n7wSzT_fyHm-pB(>)~WU{EZA zy+k-2>>Tg{0u_h@C+sCL(0afRu)&Y1UHH8zW3YMB1{!SXSSC=+93GCV2+pYlGbv2Z z!I(75Pq6tl@K*ecwC)d#5ag}&VNUO6M?uOF?B4B%{70~-AjhOd^YrTD?{HaJP6j@! z9IZ9aoUK1c9-W8#9^EW}pviI-0^cC{VPFssWrtMZ%{p;g?7|G?x}Te&8mi`cw34a& zmFf}FJKC$SxMk_4%%7r@6cfqa{7J`5PX_YcT7F z)>4m^6&kkv$A?0LTuz47-pd4mjK_M6(bwqCh40YL>l&EAJd~Jxm~lwfIneZH4%WT; zh5L}fc>Tzn+*?LN)2lx>?f%_4uNDl_d?h+u8%LD+dS@FYN5oWSV6me~p#N<0)$pA1 zg(U!o>g1Q(Q6)8ZM>2%i-t@%G%o@gB7itRu7Nb%$F(+ZdAg8>+>XwDz5m5sTmo4Ny z0LT&WOwZMZW!g87#V2K>CCe0Mwn!lg-}=y-@P<2rtH;JHLzD&JnfD8JmPQSrFqq@$ zoQ+EAH{>ggQPl5KEM$(mAy7!M!rM(Q+?i`7`sp}e5LRvZ(C7u8Vv!!K#I+8o1yoB# z#2iY%TMUWjW@9@XzpE?LF9-k};2*>aCPm(g2OP|?cS?vu6j$WNP5PJOJ@vhK22tj+ zFI+qo;!qh}rJzSjH?KWIOCps5@w;8R)Hf6uz!Azms-cqFyy>?ly&ejFi~&(=f{gKB zJ6XZ3Z-JjScBBoaR|Ah$(H{UkQdda}S51C5U#T>tnKQuKaqe+8>yxa7+>a3+7Tr!JYh(!$*oU zEeyCIkO|otpT)?ju2H)UxOaYf2N((Sge0X>{-nx9AZccoJ`~Au<=918TDWIE3;;X0#1J&bA8B-eT zd7GNCq-<0*%c#sdR7cA`g8x+Otlqu(Su66?d2v)F-glPhEs4P)l+O)-j`5;D@%!)B z4+FzhWWC(o?Ph4x`4opNpYfKWl2%dL$oG1QsrC=B%trcAG0NP6VjexpFx8V( zg=m^o%}7$WE9qDE6_hrc<38_yjEx(C8W}kC|OrOU+pB+eC-f4COwVXEPl~^sRMrb7e58M`6n$-Y10($KAT6Ocs;h~V`h%W zzq!Tk9U66NRTF;Qe9BJ&6hAOBO?eMFIZpFk^Gw@r-UTNs7*)!=1u8ZZv^F~GaDLNa zU*jxwT`||a%iyr)JtFt+gE?b;7*{8kNr;NTaFq&;z zd#c1zpAw@^Nwe4j{@H=GNOg0Ae(Bg%aWRykrI`*uq=FmoGl6doRkt9st}1AQT5rbn zsHWk3BfCD0gQD()VXxth$q0VTz?xNpS%CLFY^VNjaS}?^H zQtHhUPU^r%|E_;1rrD9jv4)@EUWZhZmbX?1U{Y@AC*JdL9qvdR637~TgQ&`7a&LN~ zFvZ1_Pxh)lKZPmln~83I#mjmMMX@_EnxN3!vO^%OX#hsTljMS_&4;Wx@RS<6KX}Yt zvM0uc&v;@huGV(zHVtEvQwHC)&t!NRDxD%w!@Ws8%PCdYDe-zYBe87Wo37$BPk(K?ARJz)8E1_^K1GsJwmU zt@e~2O=YQ4*e4CFC8RWNc6IQ@#`M0U900|s_{z(2aIzwh zB%1E{k2Eb(z^6uWLBs8+tSF$vzHU6ch4;$Wr`lTe6%tY2FF2jHEhDha4Z4bWdU6FW zHhGeCHSJxv(yH41N&2e&xDF*peZKcV83!P^Y{ydtAHFGYc~BI${0F)G!6Pw%;hyg_9sd3Su4+0ZP&Xj&}1+?kL@WR2b zPxaiuF*YN{Ow9^D4X7>l$^vT=W;X0QNb3p!UA_Cpc=x-tRvdd+)p?n=DA#KfY&kD=(|e58?T1Cnv!(2q zmE2J_I7!-_t;p(TbGQL`#vFYwz^>JuPg|2O&Y|{X^-!jNgIPF|mGX$U(p7(T$AQnZ zAiBTj&&gyu<1K~{+0G3$z*yjxX1_*?jWXD8mao+MZIH2_YFox2g@Kx-Y03}j4L&FJ zES2R>pO8=z=G@5auq|AX@o@FvtCq8V1~t zQQUCQ=N2wFD7rXK4O_j6G4wmR?DGg0_^l-vez@zvf4c!$LpR0ur!RZEprr8_o70|& zU@kvV@_v5rqfD#@r&<*=+uEPQ0<&kWk{?4P6Tibq2YqQM1}mXq3+`2IL#qM;i4SxpZMVIWde6;82O(PrrK z0;jsM?>^>LCU8(LUXxB{W9M{-xBF1s?($gYZ?DupJo(XIyu=@TsvUo2ySrA2Z?r_H z4TB(q5Asa{Q$ac=D@;hf%o0sV5xw>#QpbN!zrjEtJF~9V$^yU56!Q_TCyM0ox#Q^h zVbE24^Y3pFa2`57Npy<~G02`{=+ssC_%}tr@2FR;d~BNfOU&IV&^mT;-@#wHA~2`& zdk43Rnqv{QRC%VkS;qO0o4!MPJ*tJ>3@AF7v%UDj=t>qrs5LTUJv#eBD}_kydwV4B z$u8|6N}~~J;D(5|{K!rcte@PG}~w4=F@^NoN1P{uTl!1Ryk^8(6GOZq{Kcl%X!%6GVKNrTg+ z$%GQmYQG|FO?@@>_!@I-UdJVPxAJKAX0R=eeeJwqT$A5vDc3|Mx&LlqQ9(+j(T9W& z>Ay#9Vjf+-z1$^*UEo}FQ}x2geMW?Ee`_>zWP{r^Rc$YSH{Ib;M;8YjqBrKH8wzUX z0{*3R%STT}uq}cml9kR1j)X6C7*2OWnba{B)at}Im8F}^8#YnTdxh`PE9@uiEXW=7 zDGxcSBC`EPHhQ_VDhjf`&qSnGupbCC$mo#r*jSVlCr#n;3AX@ewHD;^4EI`~xgPiS z@$uKA3LZxuBcp%cvb&CxAN~GUS=|;!6XzAW?HNiMz?|G;nooGD7GjsE?E=_aF#A@+ zXd%))}KdiFjes09I)GLKh>Q12#lyxD_0IVr_a+rmop-~eg> zd-}p|%PiKKxP{F%fjoMEm%zt4bOxPmWnUhWE)LD6E;bh@K6Lxt5Bt5ARIkD4Hm#cD ztzu{4a+l1m?jtY%Tq(N))zuPQJ+d$gg0-4lRSiG!esu`|{}h#w=QF))y;zw3r|K>8C$ACJd4fcC}7BbH@C7tTYu*{&!&E>%L{V?&Cq1LX$$FbYsfyn-w zSS7$%<((Hte$@5IV0|P`k1;9!$7vfj$C31)vcSo7R`4AJhqZRw z_6w@ZSE?&7mhL#+JnV2sy7F&33{y&L8S3ldh@Ta&KJSl-ufh0zpiBlY@iUvTs|y^Z zag$F*$8u(m(@K=@?F--^6*P=kx89))?6m#joAh}mJnxP=3s^~!wJo~l#MbPcBSLkg zLpP(wuN~2s^W|zPR=~p7dwB52=wid}AC~lbd!knO@=g52lGg9B<#WTL7S?^t4Hj3% zO71XVNfVZYk83bgzm-Fbyc_<8W%s;0U+8uXT`f_doPr%)V?Flh{_TU?RM9B0*x!^STOe+1>f$f=M`*M(_wu!u|0%UW&@hahIuQG zt$zhE8!ewD1P~U!n0**j{*eFZ_s@$vGU1n{*=FyCkPHjpH*k?3TjzN-C_=*IXr8~C zHoX!PvRbe#qt-my{-8=yWZ6ubl74Uk|0Djwq}n~J$1V0n zvIbaGq&%C6%fOieW!~gO7i`%uJqkcMFaBo@Eh8Y!l~X>oto_FpKX-M}v-XH*ceL*% z`r%uU8TSNCJyE{4tL7=` zA0ILWZ`N0eV<&rlgLU1s33T}B(QqEzd;iTQ&*TJu!*`QK2hKMDaa8faR0+%SvkyZz zgxk+&uC~n<+kFr`UeSNr^n~+sV4Otz&O5ly-j~JYqBJDHdJEo0~sXf<14x8 z9!Hf8A)8xSx-8>u!6LTQS;bkUyg2uS0;f~NP%p~ zTUh8x5KR~3q~6b97^c>FYrxLUz&=blU!jM;cMOV+&Qg3S2?*O%D47OY`9UXB;}^V0 z{EULNcWqC1N3wp^kO|KH^OvD52M!-)!#&=450UEUBTrT&fND=TC?6BYLf=rl3h{p4 zGi0paI>TW33$^ufI^~14CAFb?(UD-$V4Vn>yWbbP&a6TAD6kxDoBi~4x{-jL{_ZeN zq^n3qi;w@VesHasUisgbTNfBD2vZF|y+)hIYKXPE_Ulr3PG2I;c!+18BryIWolc)= zxycIvcu7)bNOX{YA9HfNQry1Zt9ne#SLo3PY9B)J}f4jnaU-s4H>@IJt zevChO&{tXaU!Xlrm=dZ89`IyoT1c99;Q`&2xw~}y;CIUR@WG@NZUw4Ze>XuYs`(~E z!5+5w%e| zeo|nl)u8eUbY|={O+)S})i*J{&A(n58&Xfdg1(*&uOEgqCUr0RwWi@A)Q3DE-EGuq z6^8$2W5%365TZ;^BCy532b~V~>s`yEw5d;zNx}IjC3lSvkBY9!ztfOzvEd=N92d5V zj*9+szDsjM0&9_wNk#GHHq|o>^VdeWj1M1wVgdeOwVYZ`ZX!)ndoJvhS+Iv(Hv1!% zqE+$iky=YNLEy`rD}4KzaQiM}ByoN7UdD}=gHWzt&x|@87}hX{mCZk0-&7-7Rk$ZT zm586G9duv6{3%I|6*PRVPFLoR8e+$3zhFI@+&KNQyccARg*mAcpIJ)R zlbV3>M&-@IV|LkZ9%+B1P_R$f{a(SCF}Ut?+viD0gIK&IHUEFleHiTB|Gr5$ySKPy z={8hV)0nTCMXuZhGTABp?WZH>nE5k;_f@G$*!sQsvNcA{b;7%m=Rr3EN>!+y`#-X( z`;M@%R#j53AbOlJni)fZBw;%=CMJtO3OP} z-WbWB{ciap)T(|u;ONz`;8vNM#?Pep@j98Er$|y@`PP5H%+>D|F|GrG+Ar^FO4ANO zs!PO8ZS%yBGMuJ<23zEF5eLn{Rc^L*rZAcQ8}E(V(zm#fjsqIcBU^0hjj~T3M!}13 z-)6eaC(Zx8#|kP3aAv*>P|X)FJ3U;>%UTCr_mRhvlnuSZ7xj3_o8|nU-H5h}w$AS9 z(}CG+mGsKiVzxg1g6Y8WA`?>r^et1Aw%n5*=2!)uI4)zJo(%LqeIM%l_!f@|{gFX9 zmy`g&o^SRQ73Y zY*ZtYrr{YB@iPkk3DalY-x(x#Qz$9#rCt2-;uaeWL7)0q@YD};8)3=C)9R;LQ~LC< zwY^^|2}(ziNK+8dUa`9CM<3HsQ2%CVXpG#|09HQ;q-N;sEXRx3$2bWCC3xe5e?l22SY-w3`a82HqOoi%N zJc#SVY%cK5OHo4OJb^%;IG2~tDvEp>FV}V)dD;E#a*7Pty4<@QJbHNb?|5m~FJd;1 z>wOiRvr9}n%0QI%7A;>XRA0xECfMGdBJdSH(C~YSt!`*UCOmSNOQT%odc>~J!$Q{% zK#&qjp;)lkMXta50T1z{`z-!(dCcb_jTGXjdw57TCS8s1EaBFx_Z5@ME8OIMsY4n% zoo#vfd&=@>)tyDBbb|eQSOhcGf3gQS0`mv@z2Qx^pb*mVNc+`=s`UlM!u%!TGFtrV zr)r4bke;WdAcTUjh(WXnd?_oP-j$FE^nWTy+bFP>#-s%PWQKs;eD7F*Q;zO_f1`#c zR`!}F=X(k8HGM%t!G|i`-tXdZ%6avtzm^^JPpT`()+x$Uv%dsirm6w9U*C$Dst>wu z#|L8tum88hlT|sB?eC6ZePlsVjF|W+>joR>jC~|_C_fe?XSqs=Q228=TCRK?eS=NKYj2}^NAgoq2O)) z?N7H+Y=d>E`#pY$(0fB@7R_0^C+LYZX%L{QkupjmX9_B7Z)cAPg)32Oy$V2I?Dw&@ zAHwF(Yl4qYx5M-{2G2H5lJ6nZ3a2x^NIu&>-P;XeBcIBSz`xR{?vod>VVqf=c4q(A zgR<#9u6VZXZ!-@HnY%8!gNM2$T_BWlb{?(#zAx^j3jVYkGB$krv_F^)i(%>4vv>u} zi~<5`@m|HRt-rp%_NHe{>6WKc=<-wzm+>||AaGI)@kHu9pUA+hhwbmdI%}4Y^27a; zuz}}P@8UU&c9Rhi=aDC8SN*EFif31)$09alqfU+L8ICvnoPe*DYxde)M`l*Z8N4Pd zz@^P=0|pm|0pv`hyZpBcr<)HC{{;kzT>P*bdOjPDplM0>lcvv@W)fgR@fmoc1N+a4 z_|Wxg=X-vU9DShM*PZWzA8Ec=w$5ipQXmThH1;du){_`KNIELFkBW<{qO=S;^;7XBg#QX@~zdWUrO475kW^2y$1aq^B2cq z$h~Fgk*v0<#R^frm=C}+I{a%Ez$cNX*Uothf}ca!cAO2auKPx8FYY<&-(<_8Xn~`x zX}D=RJf`sd(fE_A~+Bz%HU&d26pbjW!hTHrB9~% z4I0I)V*aB!4q$s+=ta&8BKp!5XXUr-2BVG-BKH;bNoWA5K7mj7LdyiR;;aNx#E%a-zlCUO6P3=mG-GCOYd;ARPB|r!xPEsod@=H3J5pXVq7`*gdClwBGR`67XgMC2 zMo^}9BM`ZC<)m}^TFxF*$Jq_F3O1E)6IB~zRp{L;>S3jFxcw)*5t_i_;D8-WsAnJ+ z{OS-lfhoRNb)r`opEJZM7xw5A4&c{tPY#0oSD_-SL(B&B@A8pK*BaG9OCS(DH{ z{<07`Q4F|C44bUk^{23PO8E{rVmaW8a^&LM$o1Ckh~x8F48CV_dhSlO&ba3|10Yy*xUf1OIYGu4t-tC=Rx zeo4s>Ii9VhC--j;p(i?m=F)NUbQ(V;LCLlsg#eR~XKOICXVP zP!$x72lHTHn>U*yC|+ep?C%Oo@M>999!zb1pz>Y6xk6OB#-(_zF z&R@)Re-WQo*3TegxO(nuyacGBM9v#zsPg+M2)Y{@OS=;L)3LLi4!=K{{<(Okssm|G zbCMhBI+|Qvw=?3Co{vq;m_`j~{|-fH-u=lm-Z9~B{0RFRvw@83_tc~6Ss|h)2J1>Y zee;Udv>|_rEH^JEx=)A_Psn5s>id@Tf)M^uFF9w3a*>ZTBSD$&0eyTor|K?7{OUdR zHcz;U=)p&~_n@V2CmPA|={%l(qcdbTCIG?v1r%iZkdK_=$2iI5Di99dVdR3U!R|wr_%UHa}j5mf3`&SdY)XR zy~#iM;nIG((H`!vBrzt@lW{bO#`K(%&1qF>S_$#|w9s`_>#&0}RZSafCO_~sx~QQv z=Mz2-nfWKI)p?Ow9k>KAAPhk`!B2=qfq*2s7-iz@zs)6qGAZ2Y8tZ9T3;36RypqdT3Wco`2DNZg0?bN(dcMnV1V@so`?tQulQ= zTDkS(0nf=s?p$X)W-=3&BH6}BEvzvqT<4_I7s7u5*GT9Dev@>n&7rq8T5Iq-l6Ot{dW=liVCa~kn|k``jpJj? z*<}(R@R;#CsAVn+nW6@EIfy;GN_4|BcLTv96S=Q2dYI>cYl4w3K9NmvO1`sT-m8bf z_F@UQUDRDe`v*b&2yXxV?-@@Xb}*H!NfQjqDf5yE*|e|V7YR_bzu_qKg&suHIZ;wU ztNRc7aZEKW)z2<(8!LuRMBe~`T5c&@@8=yheqttskFa?Ktf_-?zM`b)F$bi50C1FG z2fOSun2-7svx?VUt$+`Kf&x8eY+z8Wpft^Mw`3svUNpuT7kJx|UYe2jIE&G>;i@qb zmO;GtCVx~N2q6DN%_=wYFxVUMon}7lELL8)WHSCv5O0NoNVPu-tkgGpbmLhj#Us#+ zHJ^OPkI^C{qzqm$O13vZF~y*uZra4SG`FCdG+l<^pU_RvcT6h1IoRZ0dYw%tnZ+I# z>ytSdY(3ZbkSkrDZH~(OIm}biT7@# zM*XC)uAYr3qcVQSyPgwlw<^}dv=zWOkh(D%-D~3Kso%7Dt@egC3&AGf(!PwRu%EDSflBgWZnWu!@7TzR&0dCA-msNIH#*AK<* z*d%`uea)NXbofu#Ilz+ko=qFwqvSx0XiVLa&1+zR?0w8?>h|UhBhfO`*J_Ca300X^ z3-SgA&*>0mn)+3#?r#OrMau2D+8bVM@LXX*Cbhv*5V_v;ab@%%bPh2lqexm16!zXn z4nC4+8+qu!TT;!Z0dzRp`Pxphj5OnQ9oFd5v-5GxV2%ex)lbHk)@!lUwa$zC4&Onw z%1;X9m|m<(J`?bq<>PS2_BpVBqodKJum}M zRMXr7kNAdPb=MgE%4}MPi-#Xed$%7F#A&vUSNgH@A!kzfEZP!0j^M0=cH?Xn#q=5_ zNs1gwJk250rNzCHEY5^o;PRDk@y!{MrsT(=dblzlMTRnvv6gdpKyzPBCjvW;2hq@E zNz~VIhw!CH_M3cg+`+Ta^reI&GM#TjjoKQTs_}F4`!)mBAYAPbtaS3Md&*1LgJ@+^ z{Yi7^vu;vncDG&I;1aNPgX`(zh+X6S%bzdijw$AHw;x6L(Jl@;b7;kCKt1>u%A4 z#bhBt080NKMWl#GWR#o_>pg%w5R--yojhE8!83jnvf$Vpd|ohrwn;u58Px{)4S5e0 z0Ccd@IxS8Ow3IML|Djcp#}rmLICCQz|bBi30;)gTEa<@opfcB*4fF zMNBXZu&~LR(dB{m#n(+&fcQBFVS);GVe}Ar7mCE{w%vVuCO!lb95y~{?(&AVkTucHEuqGnF3sADTo?o1TRxj{&~ezAC0xx! zo~fRkZ$~VSq%X0O6EKRO+P=-MBgD~*!yZ92Tdn^-7&(G}O?adUQBav0FCzs!z!SL4 zMt%cgf>L~E5cGeDK5S8lF3ltWLdBX=LSNj=TghcRN$108!UI$L6iJK`Qu3kv^(uQZ zw>|sypM&BNhthXgICQX%7jFgc-m#BtkPCR@5#vtw)8@u|^6J9?K&=>airvLZ?-G}L zoRn3|U&SLA&*a^0tN=^ZE8lC?lZh402Js@*b*KR8;pRCd0X)!Pe?ar zonyHsXNGZBRU;i==H%;#NROLMOU$mr{*1^z1I2(%x5JFLQOS4{Kf|P#bd(VOHwWZl z`qKB?!_YiEH>ViAXV5&(8 z^51lT+sb!!an|$RDyr=&9`O-CibPN%%{$Ux(a;Y@?mLxoVbb5qJb`UOpoJC@152G= zsNzhZWID<7Py8GQjIfiKfALSQ?R5I+)6%6t%^Vi{BYSM!+0nsBw;9`dvSh|avEI3k z5~3&pd%YTDLI)mi7VL~!lmm*F2f9ihXi0P-1ZyN&UFbNwsgmCN`(g=Vzu4T1*fw%8 zgV}8B^51|}`RN3Shiw0{?dOlM36iMSvJM@q%rA!6ua{kElpEhS7}ft#nt( z01E$|s5r7Q1xFy)E_Qz_^p93lt7{IuQcH-V0Rw%9d*ARwVCI(P2GK`n!QerRnIn6g zmyMZ8gMwi~K#gk1##5Em)U!6Fq4ER}WDr;V4bOe@dNb%RZ^S>_OI+kZcu~-yN7HnBV8onKubZfP$*ab+kHdWyWv0~I z$QpVJ)9CuXOsiCu_)#%$a$0()4{RZck9=W|5{$uT3sFeij*h zIUm#Pbc{dheqvE-jf9l{JpG8cID4m3=oq4?6jUm!26YI4m|9jDktlOS3UgBB*C$GGCb0nntD|Ux5a{F!aH(oKLG(m|%aS5m;hc+^9-(o1}iOf3E+$Z2OZIr8bH`5sAf}4?4a` z1o?*|iPKE?6HC#74@mMul(ZPWDHzEaYZK7ZrVG z9H@sKh6ZvMe`5D5EpEPabf9tjgWk4s(RcF<+AEzuc@eo2tzFG^VI=;3BW~CvTe|D6 zzHckSZ^`_11*>z^MGG7FzZ982- zrguCsAMCzs^$c*-fO^uN_7&jG+-vkPrj#wY&JKn3_L>|W*+wExx}VSwddjl>lZ$#y zk~1^EROe9`>n6BrrceJq?QT(SL5RmZ)2qR+KnqM=JWCBMLxY;atMd~&Lhr?t3erp< z`yV#EJd8i?ZmxUt|6YKC7h42upB<9kJ~`T^w{{&UGoawsaO;4ye!@;w$cqa< zvNST|yZzWRA=6mYfH#j(m}S&1^zaXD`_aWn0$^uVJbWWyoHAIo*jOB_51qv3EN7eR zRP!y=kpznZtvMH(G$DulwJmULnb0lHFJC$m%6`T?#z@BiO&^hOPd4Ib?xe~LwBWzc z`@u-rNXDXZ^PD?EGUc*bnoAYT#wzSeYZsUD-ilXChgF=4CMb_no-dBrygI&g`FbQlo&+EOU9K(f{9mOxc=N@B?LIG?8cZL% z;p6%|htjXoMYUxW=(ssVQhFB1CNzS*A^}KIXhc^A`oIRcOEszm$-yGR=i{qTA;=7? zKns7tUa92peBD+R!<%f<`lQ{E$jnI@ViWfbQ)_#ZiG^mP@BAWahz-~3@fjy{k;L;# z7B<7vmuzTh(~b4fZ|I*&Nx1D|kK^~v7x!+ycZx*jV%tqBq# zZt7n#&4=N3FoQCAQ%wO|6nI!QM)^nJ9Rx8RZ^ zOjR;sZFw0T&py6*cwyPT8?V~HoPR!WvblNbo}Ej{u}1Z2vvx?|YRa5)Fd)zz$SF}y zDd|NQ42u)9+I%;&kke)T_vr1#;v88-eJpr~;#CcvlRc^)yGj|q%&cdLw}QFJs4A=O ziWR1QV0+I%O})@d?QV#N#Br`lrU$(&(Tsd_vy{qaxGEuTO+;b>E<_H9&?9wHyzRS_&J>f$25z;}e2_E^RfTIJbvflI+;4Ri_ycyN#pgGg7--~j zNRu`Os>cG=J%%TLTS$}f_81eYyI#+3=;41?1o+E)DT?Fao%8e^eaKL-Iz7G*Sy3(N za{YRb(ajPw$LnS268CLx$#=Of>8OCvO#9NoY&|!0`tazx@Ol*Rw!wr_hOPmbSlBd` zRFsB|H5!zax2MpA7NSVP%Q2_O1Wm^yT}%gP{W4>G3HgCCoYn!!Q?nx;mCqsfSp zHtrELnrK#FdY$>%vjzO2T)o1oQ!;|UN6uhw7CZU@O49aT2;;JCjJ!M!J8B~lT14!( zws4*^K|(&IUin$*OK3d`qEPuM#SJ&D{Il#?8@mD|S1%fHHc}J4rlL__K!E z?dXQ~wx5EPlD`OA+|swWGmigSZYLR5ymyh`)DS-%^OEO|!lc4XHE)~(ckvFKnV zA-6W)^=FP-Hf7<5B?^%}GxFcMm4#)_qzlH(DM5UTGz@ zzBXfmhGO!0kSXD7^yLztzUcjoakPj+$mvnJVjjVUf#Q-cddt_@jDH%4zLrp0TtAd8 zZs^gxtvR5N&%CH@JJ`<>kSQtLto6?%{;Ijf(_cM@KA;1R?IOD7&ol{ z3YNtqx3pZU@p#?mrT|wAP<^N|ZK)NF;ZO%y*+;;`!~NxZjMzFkXs{yj8gG1UARlJ$ zv{*Wzf+HdVovQ2-MKcUX!Bk|qj$v7m`+FIvEGp_oH~lLRVimvL$?C#?7Zi*jT3l-1(Q3s=);FI7B0YoPb)2K z0DmYnFUlacZSlnP^ zHLrNL>_=1`RHSPixqM+^FkC$YVv+ePPs?9QHTfUC&I)_gc9g~N(H<5`mAg*}<2E%5R z0nt3f33G>v`QRz>>IcJj-byx_z*hDSfdKuq9HNoCAk6Sn(4W)5WQWN>YjZrN#sdw* zct+RjBmSHF?4HRm*fkwxCz%Rk`7*}**#KtpO3r3BCD&H3HPX9TY~67NV^(2K)8&Cb zI6Mz%xLR3@*pO=*dC=3YXB85u=r)FY%V(hh-8hJ7QaxRuOBjdJKNqt|($`}iAH3Mz zlW5)Fv8$3oyQzM|DRaWyO<|5u2Qdz$AbN8xR&CNsXiuJQ@OzRqD>5e?Q!^XbN_kzf z)d}p7_(rySsONKX0lR&X30%HQ6;&oBuP;wAa^rlbT?~Jc}WcK@Fwf#`o z_HucfVzydEhE_P?b z_A1vcnQ<$(HVur~<{A%?lhz;7rNa<2@lZd{q7^rr{5h_t{cUybJ!wYxF=jPja+Qo$ z1uZ@e>Yef=x*^Rd4W2XneJH1ZgcaRz2R4t&n5zFpKUQ;Ldjzf?k19d1r)vfvI9~$| z3dTe9e<}7qWBDZ|mCE+Fd8>#t+}3k;&!zat_L7`BR6IC#v|4T(yg7fiFYMh)QZ8;G zoU#euV))wLrgCHLRbrAa*1Z(hV(2!^Vy_Q4#ttuf{PP!UMLZ*=GD#L&Au*Z_>{{Li z`s?sKZX8tiImfA;b%w#bf`h$&!f5R0fzfeG>S^Q${ND&Dy#OWfqr|fHSRshXjNI}V zuC1MZ7C1Zw4Q=BD&(xH6+a8a8-N1kjE`PX0Y*M?jwXdDH@lyfRW`FpY7k2?#w@aLE zhaD~*E{X-Y#FW;R-T7K)1=E>IcvV+#W91#yzLB+>CUWb`8()1kJx;lMGEW5H!)|Oh z-m&Q^sSxZ%Z(wK((&!9E5Y29iY}G}MZOvL#z_?Zn+Qj+4uCkXg2^IiU8d_R%k|5?< zK6leNP%Ob=+3DZuCQ9RIWzhC~i?(Y%b)^))eFw6$?Z#pqJbIeqn~eQy1UPsQ<)$qSe5o^rSAJ2iPNAsi& z%R$H3HUhrv`g@AcM?5C)8gG(}bd6OMRGh{Y`i6hkm(5kxFQJ7SJ)%SfUsK+4#gPvN zvSjx#pv%M*V+#IBuPZp>efTPyGib1Ayc&W3A~Sao!6kbW_7S)Cba$k3w^2lFnAKpg2HP?yAAchz|%mFkir!4exDXTHDa`_aA5+7e1S&uyA+PYCw(8NC$yl>4=38Tku3jp_beo_YlYTvZ*9iu zgA{q|zJ;wa+FX&JhG)4rc4uZh5Eeh9{*7pYQHcoqt}4>+COLPY;ex(DMjGrs zIbk2S;*|KMBo{xs9}=ldNWsY3m!gH3Y96UeYGu7O!mc06*T~#~!7MVznr!~9S@X8Y zOs4_8#<+UgYVyV2k=B2UN-7B)iUnD@zM-MWo97X#8~b}f=%6zjg(g}wgY1z!gwVnV z{PU3qIU9@ukF(>c8GkC(pE0%sT>U)+wJ0b}DM$K-ZaXpyzxmC`{Y9+0$Vl;?R?y_h zq^;E&3jJR-76f^IO&eoc2xtD$&-m~lcI4t&JL#yM zi%8~Y{yV%To==ASp&7-5SInNtOlT#{ajM&-Q%%Rcp_sWm3SvFS)B0(-79N)|7FAQ4Hpcvj z0<5hITXszz^}3}i*k|z)kiHyp)|tW6x-HOt{Fl6*<#ptD9>`q$w7nX@&9J_Bu`z{u zD>(vFP~Z-$8nK-P3P{%7z#6%QAeaB3S$LXv&WWS71wwpEE*OjuUjA#sTvqd)mODk6 z#%_NqyaBoV8ZG&2Iqhc;eYDIA7IG@fG|@>?jH}p9=fiK16erF?3UcOV*eGQzNDnYAcuj;F zX{=1MUn@+i01WAu&`b3F23h;ym@Ec3W!0BKwT~*V_ZFpf5r5RTMV#9e28r+D)Q_*m z_SU)n*EpUV82u#-B^2v__BwSM=3HqlR02A-k~&njgv-F zVGx5E%Z7y9EB(9fB^N-b8KmXCaaVTW-tx;>sIe2ZHnzcRaJVHs)f7W|Xim}NAm*PV z`qRMbbtkClrSK~d#RD~-CO}GEGcIR+@88Og$#$EFAi>M8?PulRA~zUqBG3Lx^M>BZ zNY|~#r;g4%{f2bXv~m!}ApgnwCU?!U!?6n8YJW5t8WpjY9OBtx63xtw{F~7GpVL=Vt9c< zA*PBuE~lFUpf?d{!Rztl_II%~GtNP#<(Z7h$@ulmu~vij9_AhiA%R)KV^h<+=0-nc z@^k58WPxs(~+lIrV^UC z+63*=Kx@4nLtv#>ibzXe;pZsV+((7wGu=$MXK>5+dWpYVtR5|b4$_m;zZ zcKQ+AuE00t<3A&p{a45N=Oo@l=6dR*KaWB~f-hDUHJtCLnPz6())dozbK;X!=F^%F z@KqhA?~o`qf}+oscmFxAA>9ldu$m31A^pbL)_ePV#6D<_JzY|<24mR?wx8t>JW`(E z8BIDGfxoD)FLrRrY+0mhK!vG%OJFN-Dk;TNH}im70__JZ`VG^#N9l;?`W*0b*HrI{D?{zBsON)#SLOH?SC;#6>f5Y$-!R6&=U z??8(U(ipgrg``k}R5z18Zscq{jo25+KkGgg7+-|hp5o^(&)QG1Ikwqr2g|$>ss2o| zcUWDs{j%)A>C3*2(xg_Ep`J9dR#1cwO!gpnaaju93}XH8ynK%5?z7CblYoErNoJ0^ zC%HK@8wxgCjN%Nq&F{*J?AwrgR4)a|yXoxov5JKWyT4Jieekx8mKunbCO9UU1xh~Dy)X)|bQ9Ym1tz7((P$l;34clN5ivWt2pO~(v zU|4e`hC26Lb1L+l4~CiSHdMs%ubHqIm%3T6EmxB&@!3W#7GpIzIaYtO2P16e+gcvZ zCuy03y}XX>U2P^WYDuk3z(l4J98-R0^}eZ&LP zofNsb%KX!wZWAw~RGg;qd>V!-i;;8@inao8c`k zAZ>gHahkfKCjuv+y4cQXIa@0TgtD@69G}jXI4U9K>osig!{D8ynJ31?J_(aD*Jr++ z`|fiC4O|zT_UqN_v3F!U9!Tz2%e?}$9izgYvLcy$FKGY(e!kLcH(rSWM6kAQ6}7z*g3nWbrMmqDP7Ln#Zml|=armMmBe zhQ-8UOxK2*`o_kku6^LY$sd3{3_n_MtY7B>^W6uxpYEq#*K^Y}@uPG_92UYv(k*e$ zO1EMX*av#pwh8l|$g_bb4|govr7s2okEb)*PHZnHuQrEg$lN3Gh|S$-5^F}hFP&TB zXNi5D>lC93IOY~PI>6_$ri#*Wvby~>yI6*Z0t|Cp1LVqKn}co0^iZ+1X#i&Xl)qtf z)VtY7F+lTX87aGYu4vk?^wmI8DZUNSc~Tf?oo?+iu>hA|$!?*2P8xid_iuT^MRoV> z)jzq2&!X#yUYIvl^(^s8{CbdY@bO80_=&uWL-6#7h*oCBYH*6dC!o@HY&Fr!^3E4f zRL!9eG94N_1*HIt5_5+e`QGAnHFImaR>;*UzKs;O?MV%JY{Fj`hqtO*#!InNdB>8c zg`kXsqt8RCr&QQ%86qM0>UdvYxek|q)#csxcJl}C`}%x*ez0Feb>x2zp+R%}5>js1 zn?aMChlcj0aZ^zCs2o%*O|RnGg{639O_a^V#OQoGv*FuXe zqa8(9OaU(nTLR!;vOi(-+b-6SSs~se@}f`p;Rf3b@bzs#M97X9{}93#E_+lQTb^{n z@9pA?I$k8$j?z=##Qm|Wfh(KRt>4uG5b%uq`AWR)9NmrC6Yof`D~GW~#)n5wCPO3k z+772J$y3zj;pzDjiiAzAGtrG+NOtEAVf~s4qP;dlxii*kJxr5({l6zGxlRRb{$=Pi z${4K0Zo$Oga96VICo0IK57SJYS+u$y8=@;^jVp3_wj7VtY$nN?nvRI#MxON+x3olRlz+<%LkGNh zLl-+!eYQ8*G!nVhzxpM(dHaeeu5v=O%pfsOCCJZ68aA@KP=1tgM1xGO%k!k%oB0*| z)gELTLop7b@fYh&0P!<{)vvLDU6RV)46MT?h7fIwpMA`~`|m9gN10<{X%e5snA3e^ z>BB1BrO>*|6W>oHVx&EVU_Ezq*Y6r=2(IQv2Ucq zd>dx>IVp$B=#pa<`v{)^H&MV;(`~yG9v!5a`!J+5eiw!p~E}` z#+05$nT%@0oX$(ELi5Xn4+(fD_Op&I{$rU5q`w=6BI<91&Ewmj6!$NDv)Q1YReck& zUXk*%7NVis7)-gFphAAW*P{XqF>9-$KuB6J#04?)s|u)5DaCNuy{%M^>_56f&z~Rg zeuM2yw(XtPxCC9kydZA8c*l#3mfeeB3m5tu?N3Dj9g781@DW2MmGk_hwOxvHmTLjh zw^pYsB#Xw&08sD(Q9fRbkMuzN)n`CVfIrf9b{3iMRiDGd0@xIQh}d-@P}@$%>WV*j&!QZlhE`1t|qNH_`5~ zxLW*D(@?X^PT7#(C-YFIo(fAA8J&vt)YfHNMrRI=B24X6#mQAO1OFgk%W~T)Z0CoD zNv(d#&!k3Xt!(41&`J8R>A>U;XguUy{%m_wqq5S~0&nDM|K;DvgUwUM$W@p2^FG|V z1hqpSF8P*jHB@*oyRVb7L}pgH22?#XsGfvN#TwQDbVZ8lX4^cEms%e`bFC^2s+;L6 zi+9V$2PrbpOUecL$hL%6tEzA#ce20S`mT9_1lQB|S=#8CI^G*qP%`L$xG&fjfrG&SpGz|0 z8@JCw8MhR+soyfjc~VwD#OEXTzi>5WT>e~BJ#tySc>zpxJO6aG^U?N_SkB5Sw;g%X zw%f@jNXkw?%XI!|LKR3eVEmV2#Teh#x2zMUek|msq2`)rx{-bqo&ZO>_?OW&(T}%P zAm%Vk;PL_S|Gfa|7fnQ_kvdK$sW`@sZ1jp+z z$%U)A_TS-gU>CV{q57{C@zJS2@LrH1vGr(bZ<8}Q&NGM+#KY(M2=w{GeZ>!{@WRBY z-;CeEoYiL(vi5T19B1d+nwpxip^Cx}nmTEGZwj?RR6yLHI5%U$YI$C(*zlC<9;)$M znH}eS0D(QWtGw*Rg!qUO5fQPrqT^v`K%pi;#2Fj#n_8q3ol_U(ACD%qOz5+98w%*k zL)HpSi>LlQ_=*$GVInnRnN!8IrC%AAzfP*Y4H-8kz`wGO)D{N`5OoCH?$B=5C4Coo zp|aOS;;r>Owys=zceE9;Qk{%hw(M44ajM5{)qcH{nBjT@7qCxqihYy)!6ZZ;%OI++ z^Vk@zRiDdT1b9a03vX(!`}Ou#rHl`DDbpW2Lu0Hf)dMe|a>Xzi7LSN$yvdf-(0u;J zZ0N)5u@Gr-D52C#&aFOM(pPO_9S%Xg8^A@HMXzKlaZ-e-3~ z!)qqo`MTwa-4#?FRs)MA85xhELXJrSJzO7{9n9}frF=Yzy$&&GLau94RoEs7GxD~q zX2ZUe{+S%XHP%0bD9LS1$lY+mD+E#5C`Z5*-Ja0Ei)RetjLKTlaGN(MoYW~CoIX79 zW%89B(5%O)#|&SVOeBzgH7HGJeU3eG>jMG&_yLl_j{K`XPl?2r$~daXVDdnETDwGBcEta*CuD@Ptnfb?qTvW_E`yoEJcJk+_6^l-I!qem*?&BQn2}4ck zuy8$8w*7DK{O`-MiKNt$`?vc(++KjX14>Q462xx)5O_G@nQvjWRd;JF#Lh0=-!TbR zbhBX3=pCs=j;rz@u1KiZQk35fl`DZ_x96Afo6E|}&RX|lknErGGM2ipJsY|~5BoZ| z=wN%9!`r$KerxZ`-ga@qiQoG-zV2W4?CfypF4zTmAQz8zR?lA2Qm0A=Hq+-3zf8ET z6{Q+sM}{jZz2QotW9}hMgX~(*H8s_vO&;iy?4Wn8T7x4z=RN9QTk)s8QB1zi`dG|V zfS6lax;3PKuW!mwni}~RerQmiolMNTb{25~5y=Z)8`Kg*am_)6-e!rbR9y{)Jk^<+ zXWO>O5eT|xZX{Af_%T3lMky)bsoE26v#XxrjIBt7Bu1@ z&IL(FtgkYL*smD3|8ERp3XzQ@;>EDn-dMS?G%mMcB7t3&GfZC0NeAsLl9uw(9QIH4 z_hM|Rk#?VtZy@dax>ErNGJk8In*IF}@c#f2LGHe0Oh$h=R!UBHyU2Lb3h&K;kd2sLiTnw_9y8a*k?!zU%-e&dtt!JLPt2bUhb!NRR zs5{eLnD36p`RS$Je77BQCW%q0I^9+~VF%_~=hug6o|T0hr&-cUrW%c+5JCvXfODp_ z%8OEI8OQO=RI}S^=AuZ2Y$wrlr-4b*ZnkEorxXy^vOTL~))+{A`>|_|96s1g*iU~= z=a)Xv^nmxhPM_}O>GVT)9XP$ZN?KDZfy4 zEg)hH25H$y;$|aOLUN>L5}iEX>$IEgRwL$^YhVbZDbLHe(MVd2vdG)b1^|wV!O^`3 zI_)VlP2$+m!>2Zuo_`_QZ5dSSi;wO3=U*Qm5Bm#K)17Wds$zMqC-bt^X?HrwGN-21RNgNeQbXx7{PJ3-@ z)M)~5;@+79jc!W|oq#%Y^Oyhg|MOS7ErV)3ayR|##Wy?6c9Wpd>2Q_*^7zt2w_Q2N zN(4R5azs`ZqSJ`hhsA6sSz7NO**l#Ua;g~WODnyI z!F;FHobG5@q=is~q$MZN$kMFLv!W=Y!D&fTNs{IFB4Rz$`E&t(9Kk9_|LhIIB2WL+Aw2B%W z8VP%AvClzVe`sH(p^@N5KkYUnKoknHLP(*qVK&V3o3Gp>wSH@*KQq%o#>+xztpPx5 zh&XQa#)tMyB}sx&ObUfoX;IF0;|PHz2_X{7TduxhWi;p>e*F0#zqje?m-xCI2;a~8 z>KBf@eDbxWwWV&4Jkz&!}4ZtW~#Ms@1ZC`IV$hCasSDcjh9}IcYEJE ztov_ImU{ig#q)c*O-apelaGc&(9oUkFr=&yEJCd`XDly8vl;ca#sq+b!z`5=N#Sg_ z)#)bLIBT>L79~mpATo_xqcLaV%7firTJD*eOWIwfX?iMw?u|cx_Lbe<_YUj9JJio# zJkv-TNA}H}TiFeeE)JUQt7X^u#nT{6F>9#;b*Isofm)XyLbumwlUaa-NV>g~U@nb01 z#&EcQ&;0W8=-8p|TWiCaX58v_(kxA4p5=uo<@9v7zcq?Ly>x2r=#hmq(+NVe-AIxc zKsS5|GEIy93kl;hvCfy*M-Vp}F(+L{1Q>J9Aj`{MFFn87J9KcK6tr7Ssj1V6i$Ww3 z%L@%02sG1bc6N^OxRjD7SrTD7#HqPiL3C(-`rOjW-ov;4=GQB`z3)%nx*Q1K|GMR7 zzPx!hA3%}GJ#&%Pt$x4XY4U{QbgMNiWUJfGvO;S$8s|KUo2^8MsxMAU6>-L+D2kC2 zaK;qE^7`iVbhF9Yv$NBkPNUmyUeRr=us#3q42to zFIU!;)t~=lxA*!`p7^0^yj0YLQ=D>Mr)>> zk8-71lEgDjJh#4uj5QL@k+HZPBjvehwz!mfw%dB`tz|$wc&Ifh+w-&YD2nTk?w2Az zwZ8n?iK*S**?V5!{KCwi{p9(%W_N8XJ$zu6NF=NYoTbH3l#(;X7;;RKh!2KYyAzK~ zJ=2VYA_6GNa&tI7a`>Q)`(bdFaQ>3c|kyPQ?rduyAwy9=~g># zOwUc9-`Y5K>(l?&zxjW6dvot?J@ME=tn$-Kn`f3+hQoC4>|D%wyA=-x`P^(nl%-Ob zG$6|%ia2M~?~lg?For^utqyOuniBZ_x!HX)-TtT`j;%;)2ETZL@Al5#^Sbed!PR^A zKmXd9ab5z-7?VcQkfn~e%1b@nN=$8~)#Q1pl7x*@DM}?2Xv|{bQ+vAYsYX)3)ZD_G zZ!Fz+-z{fPzczc|j-UL~#h)N?sjbU_@M5lOu2xqpL_c})u;VPxMkiDaO_r{Xtog@GF?8hD9zMJ)h$Bu5SAAjzZb9?5x z8=Iqc8-)N4*l8z>#iJ}u5(YZqF$_lK;X{X7aolPo5tM7a^!95H#zHi%e)Nz3_%C;R z9~WW$-Zzgt|H|uxdTTU3b$X2>-@DM7?{-(W`p7v0HZEkR+0rPd+WT7Vgv+cw)lSQ7 zW@=`k-54wQ@jv!nCY$#|RyYi~u`qGdZFT9-X_C7AcdhD||O%;p%a(sTUK9w9OWwEib z$)hAn8bGwZxivdC)lOPej5Nj#7PT5G>2x%q_C7v6>vACc z5Z8TovxjfK`Q+(0vr??~hFMwepPgwpqpjiS;M@VJb*Ifvt`sl6nC|u~{m|DPcQo(5 ze(z`?OCiSjV5-q1q&VV4tjMX|j9*whdEfoN_kaE$7k>`c$89}$pXM;Nf4aj!QzQqY ztQ2~7x-*@$SJ(R29GE>_&ivV5ejJOS7kB;E_ntoW>VLfb&{eCwVyeRnDTO2ws@+KX z>3FN8D2|%b*ZuesH~{zAryj~ze}Tm265il^lx1cf1!KG{O15Wa?flZAYo7Rv|N881 zztT_b`na?pek#||W8eLUx6Tg6*A+z}w9u#reS!gU##Yv&Mv_d^%vIMOe(}Zsd$(Wd zhrSLR{>pQUOQUpHmZg-_T5AGAM9z5}#mz=@cHga0GPm0=^P^bN%vU#hYl|ysDN3aj z=@|lKo5)#|B(rCh+6%LL0Y3eKaJIWAn)&KKEpO&|F4l!onuq{^GsdI6jU?$tQ!}lD z0H6LqINdnXOW1JSUrY-jrP3O<01+8uaTGPznp1N(b-G7(`(=Kb*X4}xVy-8j{;k(e zAMf}3S(cV%A!VtQQd*JLnlumq5SXjmkTJ%Pan5-Z#Yxg=Hrq4P)7M;a?ce?7pY8TO zF2Z{7v!6e^d}cTr=6NQ{LQ0{O(pqWKKxAAV0w5wFV~kajh>}L5*=~2{X6Np|ZS~S@To$>ILMfq?hDs}d%y2ry%0M{hEQ+EiP8!W-d#XEi zf4a*Xd++PUd+u6UTN#apMd9L~)LLn+p+W;h zKtN!{004-LRnUNO69%FvNgB;ot35L_cf-*ee*D*ezS}!{Z|jf#)gS!mCqLiV+(^?= zQRGq-Qc9&HX=R)p5!FOtWPzbpaLyy^{hICe)WZDy7aqR9M-`Rw2C?!G<+ z>vAA`|Lg1D`1U`){L8Jajd3;-2JBnEPX^n0Usw6N+Csoe&4D2zDeL!%v@vn;{?07~n+F&< zV1*1gkK#Cr8;wS*-I?CAu=mU>$9HFY?`7R|&t2!1&yR-vqR7fJmr`gcl~!6gR0KvT zaGO#fg3X8kEjHjh;ymJUoFvUgv(=rNJ+%Me@#jA1jq@MDy7J~5);HG1<6&9kmEW(R zfHF$q-Tro^a9Y8@gCrjDD6$}_Gc!GR-Bs8B?8kq*JKKBL>+?@O{nE*owtAacIx0)! zD5Ta7D;tW$NMnazM+~h45IN^Y6mc9UNz!b$r{?At?!V>UKmC*cunXJ!RIJN^@cpcN z9)9?ZGj9y~y*wKiWv)aimDEZqgY_->SNVL0@Ioy|a48Y`h=|C5G33tRlV+pUnVFtF zdc~D5{`?oave~y^$L_lA{L=a1ux}_(C5~yDQ4j(*x;`xhz^Wq0zx847l(~GBvgRLw}Md<;e zvyKWCy`w15Ny8WjG6ofU!s94T;-uMXb*5+Lu049)bN_g`r{+Dc%YpE{tw%op#g|XK z)az|z*|;)tCA6*h)IuOtH9?R20~JR%6$`!Zvv~k828I*jQCww*th= zit&kTlJMV6LjE`^XvXhpgX1*|A4F-!&kvwic>+Pu$|8L-Otu_#KSIB7Im z?atKv{N67<^zgs?xBq@O_PxV8dh@a6)s^w6U*xGM%c?e9Wq?428V{*~3k1RoiGn#% zaCFRAquJ_qXZGzoaORcQKKd>1xPI`%-~FqfJiD>Eo~6Sg&n!oxf)MCb!Y6|70u%V4 z$e0lYw|ugBotGtb1w%Xm<*@at=-S+H{J`G2YKC*Q=5Wd^>z3+YRuYdaN=H^;D z9+gEVM4^;ainJoF!C81%@7R&^ajR+#00+e@=W0y?z-*F;@RP_m*=S{b18&US}7gMp^l1n5{3EBg+vj6B<7Go#0)}eG}}|t zb5~w*rfub^BuV)ueSGGr2NH z##j{bI8Ne5v(@U(&d%R-{mno7@sB^sjZdsEKlQa=y!6Y>&GjrBl|?2+DWz22IxH%B z8&xO zz<@<8ilQiKG#l+scY6Q+L%W5LuDa!h^GoMOqkf*HLKISn5G!l)fWW7Kc4yU}s3{3S z%{0vas&68AFJZtU=SC}HQ&O3pn!VzRBPW0TaT!GZabB0NVS0!4d%yR)i(4Cu=gtfU zm7NPAl_aG=DP!koK7fz_fzX@_fQiSGA5eb`K-Ke!s?>l82(a=a8no70OC_Z!%W*oI zKd}GvkA42+iI0vJyZ^CA2W7gla&9#2<@vZQ3MsTyq>P;_APuB<62%4NK(_WVDH-D> ztG@#_vqa-cNE2zLwNO$NWxmd8Hde-?L6MI|SxTXm z0;NbR&^`*fH}ry{utK=7RydU~e~_$hXdtb%R!T`J$}G>$tem^{h8s4PKhl}Yhp)f- zjkiwrdK>9@SQM!gQc5xgQjdZFfJ6Ym-pMq!ivqz4)2LQu7XYDkkd{i7LX=rLp4q$S zu6yoVJpIwl9{cLkUtdrAOUsMHK`&1YQzE4VWdVUU)}aw7Pzl0HAn!^gjCI&wG*(s# zrwX)0#!(0us&4>8LDHA*2)}6=+qNH`(ClL*O?hm{i0Emz@k=9yEt)vj;a6H_9PtTYxx;ikNwf&Kzt|G~cjK6MEw80=JUKxBfh(poAh ziXwmW+~RF_+_`ji@goq$Cv;s7gcn@b-g?6uZ@tm)Z>H&}EOKG8AC06@Ym=bt==3LD zf2g&N&!{=O-~qzU25+?-ZKt);N(xyH$Kxxnxwf~q@u7<1;B`kAD`t3H7Nrp87}$0+ z5Q2c3G-@EXiuiR9;6(vDi3l)gFd^pzwboiFtwdR_Y_8pY=Z9~w=odU@CT5yVIc_g;yp z9tnaLG@}nlSP=%KNlPh3nx+Sj92tJdu;8kjuYc?GTmAlKo*G~jS_hIgUIGGCiUN&icjvk90+$_hpxYB@!Z+L zU@Ol?q7YJ2z2?Czlj(RKR`s};T0VMY7kn_^{#98_yX0sV@?OqPRyd2P%!0Pzd z4xa&U?Gv%khC`*46jJnugKLf*+x&2nfQLW(__M$K>Bi=2Ivx~xCQGHHrG@Ljib>a>GQL=s=(IfCgidCaIMwq}YG>(6~3axN`X6_rLR} zKl;)7x*>dWA+(ZU{GDTa9LeMGzKsFQ55<@e1?((}ZN1{#kb%#NDuXxpKobCHt(8_P z&-1H~UAMV%k&*9%k3aIltG_X>zbFbj8pUy;tez7G&aT?N69TJyw@PAlQGks3%!B{{ zAOJ~3K~yEly+FdxSdRfND>A;1NRw7livDPL&wckTo;q`JMRDD2H=aIwdNAC~v#}_J zl%yq8Oi6_X{L8C+{Wc-s4i>?75{1tc&38j&fIce%bS>DGnGg|ZlBAT7^7Q%TZ+-RY z7k_h++eY?Yb$D%Uc{CanMOF>W3FvWSq*e}ycmC|zAFpq$jK{+w&kfX73Y@>& z2KkwHd_El3oLx9Mz=|SB9NiBmk?%xGRJlXz{cS`fB9dC^EHAFPsIl!D&Xa?qgMEc=wrYnLUIM=u;tXYkZ4UxDK!|4?!E86 zvllNGR#9-Um1kp7N@;UqlK^>|gu(#t{eI}*FNl*aEQ;W0WndjxqtHX{1PF+fsUj?{ zum8?hzxu*U7mY67S4F{ok!M0^DYdp*5jYCNf>vmtYIU^_+yJ2vA8ZqaF%T=j8cwRT zA|Oj$YG~yEL6%HPYgLN!;FU*)n;!~+^vPY917U3)y!OcQ%95FnB}y$7XoXs%4tu?* z2HenCEHZRHy{6nX2y7pl-(oe>e&=u)cs>V>tFH8m91DN=y>I{7vp-(nSRIcBMNtT$ zwF>(HvCa%Lm;D&ib*ayUd53m>K~X@>>je@BecyyMoYx~FskO@U;+kXEUzAw*(Bluk z`07hrTN^eCYSR}(RB45S{B<S++$Q4}^DSUKz{iW=Cjlg5GLqpBwpY$T`}N(ZCS zz4zUFQDWhBx7~Q^?CIfPE6>JdsiZWWAgFCq41_$nqeeUp7^cW>*P$HVUKBVXiZC2H zQGn-@!PuVP)7Vf?3(CX^)Xf!A*M?p%V2S!0o3;{H>DIi0rCCA}|3y31j zibH8saxio;dGBGL79PeR&?JqcICMD{*4O1g=-1Jku3cJQauCnA!rRuEdK;vpFPwR^ z(6+H){obuF+q?{%3(qj7>2+q>eXVu`&{LXhc>4gB(r@O@q~Uzg-kH z$QT~7tI?#BQUU-)q?OVuz20c+gCfN%Z@7A8b$MLX3rL!7DQ#2&ws8ZFAaN-mtLM8; zJ~dQS-#v5qaWWkGeLA{$qVGC*3IUNKBB|ujYp?FDZGJ#ed}`L^Kv=C??!NWR;+f&F zR}`7)igb)95Tgr(z(B3T3}EtOB1iN#4pz5Az*}>HJJ6(9Q*rwh8EYpY)wMTVzwrSY zMvmTi&GO39cr+}EObRXKL?Xy6Gt8j=QSCIa?e`@L=BY62{CB2FYnEQ&1Irt0BFf70 zfzRA``mOh$4E4&<#^zd@j>@7Gu1m-r3~8CJCL*m>e>@)dhVNSrk3R9pt0zyIBlDt^u3^e2K;HY?(qMoF0?+RB zWC9Ji#cZz`b6Qaoi-f=Z2$xo@Z5q zXiz$tkV6mxD`|wHsDGYBMee7r;Q%HyBt!-iW-@Wg0_&+EXd)6)-gxtkt4pizTNIzB zbvY0M0NnrRXHLBNM!y;yW3C3npy=(0j+)c2++5wu12RO8too@L9c`ZzbB3opO=K16ZF^+#9M zmdB%EQRJ=yWL=&=6^_10>?FWzxgaxhv$+!mAY&I0MJ+81lqB$a0DjMY`WVWZtc9BjOwE{Pw0`&&PG;km8q2&s^=Dv<_tK}NoCzC#GCAp^z`IrGX8sz;C` z)Z1We z5Qt(zF^mKlGME$vdpl9okU=N|_a#{Uaq55;6I7tND8)VZ+_iZ6^7+Ecfe_%2e*e4w z^!)Q%TN_z6E=#Food$&Z2X0qr?tm@xrXE_j(`MT=Se4V9o=%#24fyVm4_W>rU_@MJ zg=wNJrGDm#&%g58dt<{s_xZ<;zxjH<-^+7j=PoSQ1!XX0}2PWykx}k)!@~NV+4yp9R4?ghLoA2#x$+y1t%&(8X z((7$z*|-c2&*)kYozKI(G-@7$V`Vkf_F3RYkU0<;!lN2jyvc24&HIj~PHp<;K=V<{JW0*9OSd+q;nk z&GCNMfD9Q&L`05^Z<9t{6h8O`pr95GAqW7zMaK71V(^vyk(HlD1R}WkwwqSYy@$bL zPd@qiS6)Ba?{DRKY7UKPg|%^dwS*YM$OjG<0I$WudK9z{F%$*XMS)&CLG%wgC<8%WyD=G(O!4(Gk>D1Kc+&SYT-L(R<{Ihg7Vsuchg*wAErml7k<8 z=bS@D0)urCA!x4a1E0VI?@AOkcj4;`HL}2~#rB-g2%?&Nx;`BBK5$pTCw*P&f$*LO z?l^Pq+-Ni?^6H#iSp2v3f7=xj1^}!>-GJgS*NE<{*6tuVgqmH?h9((-N6Yq8qb4Fr)b1h3pWhteAN)%xf3_FJdcw~ZK z=<-xt0@EsX;}_7-)*3n!2F z`de9+mcryf?(mGELnr2B`XaGa{s|-$+6WI-V!J3NgiyDXAk#yqBJPFPz~V$+2uS9u z>u$Ji{ayDJ-*(R}i%aK6qkf*}LXdG34jcK-Ve2bAJOXr}*)ivVK2)Cp7&5-ID7>jp z3c;glaMB3FV6bZlG{=LA>HyXqciwXT>_;)F@ngF#=|K2LzxSP=|K>Nn-d2{4N}(!J zw3^=HG&|@D@ojHTo9h;C5}-=Cx#fH?>>|OsZ9`!3KAHthf;B`J_(Demy2o`Z(Ey+{ zeC_ckUOsX19YyhlFFbnU)LVl=uR0W^K&xOtFirNqRnh?G@x#x7zpJ7kx15g?MUVse ztz*q_YpH;Ty%VV+)Vx4dB=f(<0D%Z_^se*c+wQsL+|tr$G$`^?8f--Ngn)Y+oLdP2 zLH%=;A2VMwW}YpWs0)VJ$l;sNW$hRMCbJ#y_}t@~P7neS;mx<+xbp7cQ3~by#(Fv) zm8CQX=L0~nohN5b8kI~Sw2?3!49f>WtB4l`18)Kz2VhM(03C8+Z%+M%|oJtA!p2FLZON~wcZxSEPfAwUl7>54fqJ?emyLbg(h#RFpRNGtBuun zoKr-H-eL7IR zR38AGDC`#wS-4CR5fRCRp?mMX?d<9EZ!d>``G?>Cq8o2eFBu>wxfp z04tS%P$i7h=ga^j#w*?MB_ctU80Bt|a%^RGQfhi!l5}tVo#9cL(AvgYIvy2O$zWo-dYvk_gh!n$@pABwE0r*y zIogpR4ZK7RC{-g;v=?B{tV zO0A9epFAvRC!PQXF3(x7({CRD7;?s#F>=Nt^CdC{hz!FSq#@e(R2GJQ(8UP|lveF99ohTf8R(rFt76$B_?D0<^4X+qM22fWI z_xlXNXyPbM*H+#E9_g5EZkh8EN=m~Iho|NpAaK;5ZS=1bfHnGL(nca~G{lw?SP;JJ zJURI7*29~(BtSr_frJ_|3`))x9s#g>?z-jdnYTM^`jsy~e&W=r!LXO-Roj#~NE(bh ztN{WyLe_T-)saEqD=JukjB|?&7^^yp-_czJHWKhE!T$Y+*AWct!-|3tV+;VFeDsl5 zPrmW?TJdRJmu?^wF|BW`rKxKG^CtxA4KhI#tU)%5>sf&EOz<t9n=D=N4yJo)jmCqeNeQGf17kMU1tt9&9cyKPs%@CighXq<;!=XJmVM3rm1DwSXk6A?+ zAcp$^x9bV`4?ezOAQDG{22ZR7fKUuoj4~7^`@+Kyy!QHA7ZSyN58Sr6ygV8Wi=qs2 zAP9+Hpaz=-iEieko$jUe;pHdz_omL-Qa0uxURP^2{zFJr4B zh>Vf>um862NGG_yxnUgz_;fHlMH-~VJE;T<5K@>9GGr0A(ujD>nROSHC??!Rz>0dC zsS%_TCgGkK7zkjXJ_eLBBt$GoZLD6RT{D+xApH81Pn8a2|8Us?!H9XkiVl?V#LsoyMA<3u8z~64eMG zhR7IjhK%vgJ$UcQH+DW({=ma`EH1B(#-Yor>K{lz{+Pt}D9CJGu#y8*&b_J&GOV(n zh{q9c#Bq!B2pMC@GzB?Mu&0S{LEWACC|OGly}zh2$=0T$bcbm&N=5_eCYn;uYV{vmVC_DB^n5$ZoIl~W+*Ee z9G_>ZAWU483J->FKO9!WeT*S+#yGc8u$i=4&6!SnKH{+^O>PjRr&Ije2KKOS=+%<~ z(kO6=J|KD)$*mv^cc8-l@Q2_2&B+r3LzRo*swqGqP}sD8H}L!Ddw+bR(Dv?GbXpO|QPOI5XWH|v zq!aO2X<5B}n8_;ewOD_)GwF7#HqDC{9aS&$q_0p83NOr!VL|W zB+c3G-h&5jee}V9QDprz?MW>(RhQ^F^{rgqL=J?3?oX76oVo`|l=~aCP6}7LWWX5X zoIm~0Loc12JV5r9FFf$(x%0!(uqX;?`QggWF$$AoYv=VSSUW4`2ME}f(TMRljv7<# znZ5H@KmN%7pb4{dL(0M3q9{t*&F;d?p&O1pb?w!UkA`RRGSymZ()BHP zS=7V*q#U3w9hVTb{o@%OaoFnJaXFqf2$u}nltbFIGFC9O7YA_gNc`l`v611`hY6-a<5Np)| z!Ol^zZZ+J8Mk5LyCsA{%Gq-2{=-qexK&wKOBdMj<7CYm_>k7F63^!Oy4{H?z8>78} z)c$AM7$VMj#J}-{FTU`~@$Fji>0WHNU%)P`m)<%)PSaA9hUn1lu6bYnan$8Dg|B+Sn1}U9hUCXjeigKb6E~c!8{r$lvFAzUW#8%4?Li}qQXiY~PZ?@(h zdlaUpu5zdH{U9!6HF>%tn6+UgHo1e~OGolJXXFAWROFRu^d|zXKuTSf#b7l2+Ls>L zE{gT7UQy&yit3=Wy;O)%iGg?#Y7?^pPiNm>zn6)VHjFXOFk(^jrW$5EA&Mej@9h8xp83)vgVCrg3n`VkaXvgZ zqIeg2f(tjL_#9a+E|Ck^YrZc4inc-uAWZQtQ4g(mrJ+Ym%eL&9F~%73>FGoN%l|ZYVEqE@XW#j>)u(SoyZr)oVQuyYWtl4}wI=5%k%)jH0HI9+&>EzxDmXtC_Rza0SZ8hQ zEi2O(U;ZzzoNSf(un?IhZLSFd2opF4paB?x1~L-`HGny-tP!o%Aw$q)nZz1q_7{)2 zzYJinYSjcH^jfth8FG*jnT<0vv$Ji;Ct`@20FfA>b~lrf%L^=B zHL=WFtO>LxDMgXz%e_hR=PRH4%yTDB3Q;OWP86m`l(1<_LAFQ6ztP*_ksqUMujBB# zVdh^CMr;4=ul{$XX*^z+N|5V7G`bgra{`8-2@rwVyCpPPL{-hyMg~NtUD6L$M$0o> zg|OGOq9!B_N|O*}nx#*D?lXV>xBnc9VrgqVFLJ3wHEG>maaBvWy>2k{KG$7C=5*VA z$(#|H%@Lp`8fU{_z3|5`ywb|E%|aGL)jhKI0$!tam0}Yyo9#G#*OkPKjgTgL7m+VS z1h;Zn!Pxg#BWX}dm1Q{`jkaq}f0UM@P)Y_v=c|9b6REL`(JIMgo2WZi6XGZEatJ~c zm=leqELT@wd+M7jS-O>%sU}5MyPb^~eMe+Ogjo42bG;H)V@@llfy4lbNLRmYFDr(c zkFdHz)m7V4ilQtw`xp6s?@z?K$TZC{mC=n&gDBU z0t0^sAfzZoHXLtkY@O+k)}@llG9AH)7FTe>Fr{##TfBeqsYX2+vVX)Sh^}C0peqq- z@>uU1UwkMO#b+PAJu5OLh0@hQX)`Q}>%3;YP{-!m<$w(RKkjV4!URg|LKMC6#_GnK zgYkwCxzfr30`yyOF4ebSAO?ga;sl@$e6CMff>-WYXXEv>1}SAx7F&bK*;-4zt-L6t z6agSW0AO;9T&e-VrSq;;GK5Dq__@ez*}CdQ5}VfeXqK~=}C90vIdX* zI|xA@Z~h1fCGv8-HC$TTe4{s7SKdaDF!)z|mzI66v1U6}+oMmpe5?t#Kgpm#1&@>> zAw`zwpL_K7P!8Yt;=|)~T$Vyt*a*YQ3t7n1|qEuPXIu*cw_!PA=zvIU9xDo3IamV zo>3q|tdN#Vl!GFXU3Pq~)}WLULJY@gs1jfQ!h^p!d7|Qntya`D4693k>p4(>$-=^{ zi|JM}1c(R(q_j5MR$6H@5?pJtDUf^joXe)_A|YcG;0*^Dk?A8PmkJ_L#TiukLzRjJ zsgO$wwFYJ2(Xf^jp4(b0%2Fv|t0!dhDu|$z(5Q5>()gg>fs-~;6Q73>E*(^$fdDiq zAOz5gG-(aA&A=V9A$tys+;t;}goGw31Rw@z6hoT~vaSgsdr&2XW^ja%GB5I_{(BhA z`{`JhTt>Jx993kX2mTC610Vw(_%e^YAdH1UaW1I6J4aCYPo=feN-Ck0lv*lXVO@Kb zXbtFD_h&ohJiX*yOwjcZ0?+!z_ZFcWs{jbSo)n@Sr8TcN8mB^(N?Y%5UV-QVFd${q zpotN2Sjz~(GKK-vwXne47!R6AX(hE(S}G-!RzVLfT9@jHM4RMU|LO2-z`}w5GB|V` zN(?MicgZoJCQ!!f6~+3?!Gk7r4*#ePZ9{Qk$+3V9LRTz_%|#>+~`Du<}f}H zks_tE5=tm3l~!7-S^y6Ldl*VB?cnN0PBY!x;qjR#7@Q6VKn+k6Xbnn($%LMH;$A0; z)xl&ix?QbH;t4Q-u&P_Pf=VE1Cp)GFr$ zS`D=&gcn|;JY@o;Q7J7%Ijmd9Fv~<)Y9*`r`&9}B0H~nphbw`vpa-=BXA=~t}!~if!!6!y@6Gb%M5iV z(nOlHt{ysgXP@Rv+}lmPMhDfRAk=^-1n%Ai2KRijR2UH`Df6QE?w3DrUc}cwcVAIf z=^#{N=n()Zo(DiXAb5wr=>WdxGlN2@4+gfFQ;EVX(nM61OTk4u*e-{9L>TOxcx#%urpAOJ~3K~y5@(#2y4 zy^s6LAv6g#;zPSD0g}BlUTaO}!(_+4qGx}-mTm@K9z#*rzd6Z+1%RoppC$}w&{~$F z7-XI(9%q@9LThE!xJn_o?1h0XP{M#LaRyR{1r8^A-nf!8*^JOA#)OUdUv>B|$e07o zsllUAW1SqBdtn%C!6GCeA|+*6mS6vDg$cg*4rl*z(U3FT{EHbPbh}J^DEFXCsIQD8bE1Tmc<`@_qRS2 z7yNNumlid;w0J^@QfZ|%=wgtKH==T!bgw~d0x7~cK#?KnM&BEPp*jYLHDq0&qBxD` zBl}Iaj3HCNZy+F59Whu9pdr)#U^+yqFOdMMQn|MOQjO&ZUxxc00BQ|V$x@X4aYcG; zj{3&s5dkUDTYim4&BoOA7BfcmW|>+F62i=|q!+?%`%jztzU8JWh!DP9%Z63-UsWG6 z#9-AfWT;UB+e%YWo(Mp|kf=(x41H)hHS35R8(oD%tw~9d7ljkhC{2}=S}P(XqHOC# zl9BD!$ZWF9ZN^>~XD$2(dgo1EVPP2 zWNuV;-$Sc8M&=YKhS7oQGmz=r(NI~3b~A4s6@|;)r65YIezxB2G_ zGh~mbOnZ8Gx+wB&w37ElA^%@;Hr64CFuQ@i5qfKbSzImSt z1ngRPhR3%o)^sE2TM44F(F#&Z7NRu&`q!VhM+!k&Y68-l^7V25e3`D6gO_c#%|kNK zNdtG1gH2FaAO{Z!>iy2!YGI*3&^CYsx)&y$UNQU?X@R;1ByE_r2Mr^JAXQ4r%)+Do zc&wz*T2`-2i_!XT@~zj3{%-&yK*VU;BOa%IAvfz0QYZ)e8xXdAJ4tx$2!&u7}V^dewH z1A7KG;aexd4b}{==F|u#z^7U6_rn+#oSdt%I`xaoy+YU3*`47F3^E7<)vF<`m6AnS zdA+3UnWaOmL5!A%<3SY1q*bf6AAmsT z-dothn^TN>D6;>i4-7#J2tE^5jGWgAD+qwez~+yZLg>zFeSlaKNL?|4R~E(qd#Z%A zQlc!s@!9(UV3-btEJcwK!C>{3bht#I@@xwrLeSQmvx&E(_8LNc2AufOHpQr@*LukS z!}vFGJfrp*Lb|WUQq&J$PT;DVKwM^~iKLQ+4TJ_8DNztXfBB`f|5_BsQWXFZf(q@i zPL0+bNPwcyD~2=YaMzZ^aH4QbdF5Glau?p*0%P%5Ei@>PNW8BIC|dNf5VTfOiZstZ zfTR87txGEq3Q>~QOsi4|&Ul_@Nzxf?yq5J(21df_n&;qEy%dBKT?6)q&bd3AG@bQd z6Ykf>H$WIt8z3PyMoCB`ARrSa9ZE>2FbU}{nK)!1Ez*MWA*7Lp(IqiJq+=t*p&;G; z@crTW7w-FY?sM*QuJgY9f5?3WlN~j_z1~}-{bYQDqT@e$p{ysFLo;iOeGs+p{7 zVq87!9YecCcwu-LP-x6t*cb!^JdyvYRgt3*4;bHcXA}TnsL3xK!4~~l%?n>u|DClP z3y?M_f4`dWyGF+>x9{q`pFF;kz4BGb?x!~SH+k@r8|%>&gS>lDfTuCZDGvkA9C_zt zu@vGlD`Xh+O;Ro7XEng!Rdf|*q-rp(_020`{7*h|EDh-c8aAUU-ngANGr1 zB2Qxh;-?nq2D`cBcb8kS}#-nRzVJ-6na?_R2t)BUH-dc$Uqw^jizj z&&7Q2^YRbcCBP~I)RS9kNmjFoZ*UhHc2+jiWegj>W! z3P7BNF6ABs3hBOb(z#n_02hguV5@}QW76N;No}Htbql$~1?6x!-eH7nB4^Rz#}s?n zoXziJTx_Z-|GL?{l6>DlUEu2Z+<^Fm7I4{_`aD7c<2%b0mv=9<0JGvW6RsVrFFdAh zaOFYbGiWp2q3MkFD7%ihm6vW5%kd@ljgIM0V#njS zUazrf-Tq6dMcI(+f}mKl7L z?VDNzpT<4~T_xyTb<;{?=?pu5Xlb3Qho4;Hk7l{>&FDSGKrWt-s_w2ROWW%s{sSo z`!^*MU}t~|rQj6SzGkyGPu<(#w9B5Z+{ZuRT zWv}fKU-MaF#@cg1auhk40zB$5AJ@2Q9{zZE|I(8+Aik>b&|!ac>8W+W9ZaT<8xBkq zb}gbb|BSk`@t?@_O@@Cbu2fTb@Aeb32a03=EPFo$W!zWa?0)>6zq`s!^5m!Fe8pc} zck)B4e^1_kRs&4rk;m~AG0XghY}yhJ|8v{;81g9667YPXr5mFr0hUfm)f$v$TUt+M zRLSo~3$&PW#!9JF6ugqoGW?WL%^2e=@n}5Lz51)RIZPW`bxT=DY$;AI?y$|2i7c`Q;tMU_tz&a*N7xbv?i74H5uc>2e(uQDUtqEWB9 zk2>zMat7M#Q-iBMe+mDnSS>(i$Ck+5&ucqCcI%sS8zRO*c5=9+;qUI^6X z4o}i#XwQaAZMN<9Oxb+8Vci=aO~@)ferPgpZ)wp2dHugJO=;=)k*Zu^-8X947!?z*xNd1oI} z{Q&oaWAV__oixrYU0(DTmU*@d^Z<52q3=Iw&NXs1?*-tJt62EadH9i7`{f1EPYMo= zJO zFOP*SWt;l|%t|l*hG)BOK3I{JMpl2d@!8qS+v}BH2r2L z6dQT5Dje(8D0%^4?)}^u9AF$f^rzKE0|=o||Mlc|?mP9}=QS&TOMX)!UjjCC64okz zbe&Zu@`Q$+wKS~Dw+5Sbt9Eicv%n9_x)ioT9#6jmrjXIV{+;x0Zxw~Lod%7Jjvj|E z%)1`@AFnVw1|K`iuYDW5o&ki1f=$lRav(Jlr=H+nXuA6ps}e@_t-PT<6>NVeA~}A= zG-BCz#2kUN317DU8(?emys?`-G(68grsd;PIfe&3Q7%8MYWLY+{x8iR0ag1#hHO^6 zfTt-h;xA}27wJ5Xb1&Ngot9gKOND77ROws5j-#{UU*r0!f z?d#p^BRc)>(+x1Zxyh%Y9*~uvCXU21cC;3_ZS&URLmrD$o-6xa7N8-u`$!zeYn@C>F6y6I!nY4$agF`Q zZqIs*?}BJwtOQ8+zdl&z3fhjKlu)$12YIKE(jwrn;{yN{&5bU<`GaHsLYEunA#{Ga zg-vk>tXz#>3&2c?*yGoKhajttoX2irCvyD&{Tu2r3oQU*k$Au?*yj(or=s3{Sl}(s z#!T7sYiveCR(#1@t-}k~*ld%QcX8O>rV77{W z-%T#7HQJSjIq`2Z9RGXvc1K%>MPFaR(z^MZ>M8O7S7xlOqqMYK8z}d++}eiSougRY z)FdC;Q=wGE&Z2|HELUZ>(S6@;XiH~HLQnsoSdDg6TS(8Xbe^C0zjiY{`6!|wO1WQf z`+-oAzK8;ewX->w?%mi`TWX-KW#XEI%9~PYFsT@NygSx9y?deiy!&*rG=V>9-EI;v z#u#tCU1-%`aqKb|&5(3(m~E(;y%W)5mYT3~0g0$ zLxAP;N(anX{9WnLj4Ui03LL!R;Dn(DBEOGkEk152_(URJF#r4Dzst=A2uG5dT)-WY zl@~_7t)Ggf`F5~EYCZpjwkan2>i&7KNICBXIv9Ghx6yy;z z9qgSeDZx2EQFgHQ<;yh8gmqZ){Lt|k>?eb>EE7gNUek4F)e#h6g*$Dbmc)Sc!LQq~ zv+eJP0}rNcn0nLhkX~IglIGkaw_KrI-10Ph+vyjcqqpR(}onA_}P}s_iqSp5HH75D3}Dt@g%0%=*g0$uoF%d2E8yTpUw99oe9e87GU=4rXB1vKRz>AhsA{WLiW zd>3-_RHF-36os5S>CUg$m+Oq*`TZI-_V!M`u>{(2-1gc2zTce}5S76mEg_Mm;Ptmq z+e&LzDjG}7rb;xo*@)J}34M{HkC?O`<^WoR@ZfAhPZH9a!D9_=`-@;nl&WP6I)O*p z!`SE7I;0}TOG!+h`phPurS0u`eM~yti5z z*4*FqYg_q`>u!9+1dOi+Z8aYey5i*NcImw=rhrNkN=l)-tvny6xClYV9@`#maVYS+ zetmk!iy^^2rv1yTJ3L)p=Y0)7DXd@hKFt#NxuZSDn()m56%~bDZ}&rob5u(A#r-ZSfN?giO;4PF!k73T%s0S=>Qa1PER9OX% zb{eq>x!zvgW3QkV6o0kbd(`^@eC7RAjIcG>U$5jtW2laa$s%Q03qAk+ofk?1C2#dZ zb4$eW8<_%t5vP6kS>w01kXvUfMB?%lLdBu&;3)KU)4_A^2ZqOATlM5!l+wK6@D*we zTJJ}T40KF%J3C>sew(gVpxyttt{1T_s;kxKYJ;P+vWqRgE6bY)YZ9`rVNn~K?R-%J zbQfo%iG4EdAvk|A;2V#Dcyjvj{+US_An0GXq-wwhQg>r6E$ebCFx=WIL!QKkP@1J- zHYMfr@Y7;Si|mGGjAy(!FT!EGe#)-a=a!B-q}sK{+sQOf!{0b8x7r1ekrPt zDt&9aCH93y-#z>n+bkz_jLUaj{Ri?r$nA>C))w9gAexd}P8u59L(YwTAuCl=QAf(| z{peBIT{y1Xq=BG`NxxTq7-~-VH~1$1>w_ds)2CzN=A}puXcwtC$XOPjJ^i0~Q3u!6 zl8L`_RKF!b^YmzIc2uc2x4pO6|Gw>`@)td6GONXKPCwGuDzy3|{r7~Lqg2zI`5$W>T>zj;%`hqMMi=*?j@=q9_QA0XmD+ zsPZq`m>Vyr!d6kh&a6PYU+^IX2Ku+pD|q{|z10uAB5>!I`R>(_P+wr^v)G1Ju!p(^ zb9oi$2~)>?F=<}5&=w?KXLIpkS9|<)>9ogHt4GV4c4Zyu&t}nc$!9qW>d_0P2IF(< zUO65>0Kh_t`&)+O+Ls`tzqNkW&xi`EBHyobb-BvttGVh<(~r_DXo9W?;TNX)jYc9l ziZi~xwP&owS?;uSOS{xIDRR(?=VD!y9b(4ujsFrkFbumgT@y6-xF2`XgNQFw-zE_A zS3?_wXKJUWG5_W|g`e8Pj9+LnBu6n&q1F^tdv-4#7KkJp-SHB6ihgdAT>DX#G&p^J zE^OKxEwhd2P1qx-$B@??rk?n@Hq ztYQM_p)Hbj_{(f@xpffjNQq$%CdMPLql5^QA5H%4pZ0B*;#dYY_4~k{aR2dA93|K; z=Ln^PA!?yDT14q^(Prjk5bS(n*oH8-96IB^r*q7&f++N+bjPz2cBLJ$1F3ql6JIS+akZ4Y_eH|9bzKqAeH<$U100ia4Uw(B5xEJcaO_$)!8^tPYx;E6U;w@m_U6X85#hRb_0KZKru}T_OZ6~Qjz^*F-dg>Jv~5+K7a$Ik9=x@)-JX24U6OC zy8d$=yOUk5&Yp7}^?f?LvHkp105vT^oUy=i-6|=fDR?iD{45Sr5vy))i^*dk zg?ycz!-`wT(L6&3d{@egESl%wZYb24ab*+Ev!4DXx|lQNlWOJq5(FPXBUmuShxNJJ zFzUoL=j~;1SIPnngvlbKF{O+NKcZqdSX^hQSrfF~e7j?f>&nK;Rg5*3 zBb1TmJ&6KELh}iW3*o!-EV~1jxoU`H#{Q_6?SXCAZWyi z?J!M=d(C~OTd&gAIG`_Hk^q#aZzIzDW}#sGKo^DF@R*dj=hPH8R3Cf(+b+}nTMqPd z-Magme1buaQEBs9t*|pJS!E%R_3htfB6+mqrZD8UxLZ^y)3<6ue|wG_HcSkAw$ddBo-6Usl*Pu%H{VvJjGh;x*i+ zlEM~ey4?!sf!0=_{}EMATNbDUG-vUMm?v*LKqP92#bMbJrJ|qbu2s`_8Qo#Uq(yse z7EeUkTSMMO`Y9g2dw6)UiF9oV1*ak~olE$-yz*>rsXX!^E++8E+K z6h&!qOyT+j3Y)+wx@1pRJ zmh|HM`7eI0ue%W1m-k@kC(e4O1%F9WBaxHh zM#yZJ;Ot*~%q>0QD=Nl176Bcva<9{DW?$BkKd#`6!Y}WOS!Xm!00507k{@dQX?Z{A zoh6RzHj>zFOg?z^gv?yDDS$)iP{i?-EfDi8h*Q@=RYMcEk@6BDErqx_9MQ&dkJq`0 z*^+AkFjR(>iF%t*UoWJ~(UU~fcw8a?g8t#=N>6LzR1bqO+*R3j-@^0o`Fpf}PazVY zN5G&GdsFw-BHcMLPdB`!7GvePHfV~$-rKG#>}_s8x6B~}Eyhx^st6)Are?KHRELsB z$JjVyrj?Y8yN-}Z(~_T!{+d6qK=%35YYnvar39Jy`(2u%`5h)8^;UX?*RmW(TGe-O zhnTQ7j|$kL$BWkNfcLm< zAF{)K)8#Dk(O4;qGn#jSJUW(wY!Sugebo5w0#tS1ha>4zCJ?4ldzIOQpeCVw zD)knchb+&K96}9!ttkGdL_%p6i0)umanJm>kWd)^ElXQV(D1HD!_kOby%Y?l4oyxk z{ahjl<6)IMu#SG}_Nl0Q_uwuiKILoeYlk^*?q_>X>AbACKfkz@589Z+tI{*vHbt3u zRDum}Ii~c`L-3FwrW{GI|Ud?qY0=E%6}wo_rOri+?)o}JqsRm6ko`eb-WeZo93lHhzt4vp_-0nTSZ1N7C`!k5UC9W zEvgAbjty}WfIS#DPfISGIWh-JrIX)&U^@Ab1<^T|7V-aDfSEZ}UWmc*5C7_;+Zb*| z4Ui`3nzW_IAItE08ko^2He}I6U z-6D^xDeP$Y&bqX2O$K3$4wzRMy??p;e*W~wC$s_D&u!n=biE6)BHe$U_ybRWN9NW+ z*5!WGFJ|K1DWF*$e;e=}NR<)gR4(~nFcpH@!c~C89;UGbw6+L&lERbnO!ECLmJv)> zHqK4;qxC!CC^!pb!Oe*F5EvLE5fih##gf0QtB@2spd0W(1JWsiVOgS6BFs|42s(e& zbCv%cpW8nuYV%jEhn-%XoQc~RYG+U0RRh@wtwA`|c>7;X83{usUvtvj;x7r)l$`V@ zM=Zy#0x?N%swV4Jf4-`F3fg%(ZOc@cUmvXe?9w5W_!-epKJYe?MItVho7>FtSWA`q z{W2{?XQpoDotzAe1gfGqeJe3ikOZ0zu>UGZ@**^HVaa3=a@7#N9e(n5@oIAW`s7zY zt}+!Ss)i$hu7KU>@{jg%tfkI$L5@#mp=2=y_d|f;ZBOGT9gkGB>r>wU_{X`AAg%++ z#;jO<&}-7b5_Jq?jeo{#0~Pl$FFJ&{3<_F^L-a4H`|&M}edT0O2R^T-PuA?XiqgiqxbT)i>u>5l9e7oglUvcedJ&?d7 zAXs-Fj!8iqj=Q@Xju0W)-JNA|Wc@m_K2!RF1Mba#=jhj9)V!Q{Ja^!#P#66lzzpsu=Cmvag2PHKcLIa2x_!3qf1)?bf3}A zj07!Dlu4xegn?vJS)mK;g6Xsvmo{=#hLl}kdTzizmCWy; z5QzkQ)(}Y0X~`0|jJGb${G3I_z*UF*oJ{9ZUQg7M{|%J;JC{+Tt`48vTE@(rNvtKy zk&@*#I>L|sKpY5>HR6zm;!W7YJ{<($4f3PL0x3|ZG~;m$`ABw00_jN)ud5PCUVnab z%tD5e`0p(a30&8`uKzY9KPm*of$Y=(QZ+jueVy)?;Qa@--?I$}AAM(9O_>yGHWBfZ z4CBwjgjl;>r@Jp+ZLZiA|-?rCRUN;C}a&(aoh%!BB=m$T;zg zfMy)yySG>dND^9br9Q;xpe_2lr?uQk`mDGig_LZKC~V%TG{BA=DwR;>Ne4$rN(IPz zw2GM(x?AZ+JBJGO*rfqG(@n`fET!yQ7KZPtb6vHzpWD1X_?yd{&>P}5$4>e~q|oU0 zP+lCsjQ5_T6p3@=QB2Q&@5wpQnEvTUkD#D$!Rq-aC>-&uv@1FThtuUj@$royoE@Y} z90?^CmR0xo_->cThfHCuM*{Taco^v3N6{re`FEWvN8Z znMl<+mCyhHpCFipZUcL%%{ki_`2XMzf>t*MMnH6J{Ui@M+IgHt1@j}N21FFWI=|jN z+Il-W8g;pMcHt>p9F#pW`KHKQ?!Evr!=R!(T4#&MqC)lsG%?&Ytc1&)Pan`ElMW8} z&oqBzeEvHhz!%d~Y~fZO{KtHBi$8*tk>Ob+ zD?s}F=X&VGOf?Y~tazxHDBRATALjFd9$p!?=~nl{oLPnXD+V)@fdVbu1R%@G=jZBCPGNrH zB=*TAA3;Giws15$$y+bNaG)V7Yw_Z;GKTrWMP3D9I{#f3;u`3|#LY<>)Qhk@Cjs>2 z+0{ZA-(|W~vVr0f6Cv={5Hg0WgsM9{57EU%+cdC=V3fW-|an(33w1YmTsZs&O2jr-p$r>E#444w5&9V|*|)mdu+?zCL(C5x9+AzZJI zI@!_kZ^%i$b_ZEOSi3sPQ%)P%A!AmP_|_0P`s3$OU$}fnmJ4|r--++L$MkHiS6B_V zFhC#-ugaMb=rILXYg5KX)~_s5O^u(#h}x-=`2U`1BzIyN z=y|F5dP;P`Nj}>$efGBjHMD3(&`ta@Rbbh;v4?>5Fpk5`F+p300Ji(J0N-iCLr9YX zm1_f#-QHfMt0P;=ORE^<$p64Y{OOlvmpBdb$2!}7i6fAgbgB+^tmm$f<*qqBbO##q zTuZ26;h%r|p*j~3u2*U9CY$VHyUmT>D(nPHOME($rzYX{dOQ#tXcOCVyFGcj-ZM-h8^R`G?32fz2;kkWcjbjeZe2@Vm zFw#Srr(hbGo)ty11uzD?Wetvs!pXE=Z!Qrc&^|tG*;lDOT z8^X0=Bmn5L{X=GmT5bJMSqYNr4a6t#NdT|^XY=V_e~nR^TFmY^ny-54Fw62ZX-aM$ zf8!`LfJiXL>pC<{efW+%u&AudZLYKHdXUEmCld*ZfYN~laj_NAyj=_ALy`4`?(WEO z-}Ir2y`$eL0)+_7GIGi|WTQxsa%^UmQbT4QL`4CkH z0I$sxh;C`On>6Vs>oRV280fch0pDo68(DQ;v-2yHp+y1I?j>7P_TPGj@CH=tuo+?~ z3`tOPOm>f<00*t*FL-jVfoy?P>F1OPL|&O&+#jTHV0uPYQ>6K5kf>wM_{9pbH$`9> zCsH`v?HYcMQtW+LLv+sBYcSA=sZ!%!%^0;k&+O$)zt|+CD_YX~ntHKjGlBwXf ztm7xuK$yX_8VoX$jR7SMvjdWxP)1$ltI2##hf{3!LV|Qmd!D2^<+60*rI0DV&F0|7 ztb~X)6o`MsFcVyS{CrRJnMw`J(e*MjGb57(;3FC&zaPkTk2MW8d#WxLrl1K%T6lnp?(c=JFti>`Tq%cl?^3bUb^a2fuy<`-p?~?F) z5q1lZRBn7Q_MMIvgC=%LI}NLZxP^s%9kP~$IOL;0&xxSYKOtI=+X{`yr)1IuyMWF{ zv`~8?Z1KNf8^|m>@h|Eg`rlOO$$c%PZr$U?OxW0;Dd%b6rJ(biZitHXh9N;fD*?&0c zjV?Sg_cJpF6^hi!GD#-PS&-Z_xa|{2p<=J&>~cev%y9T;2Zt8cCaFQ1*Z|2mzTuLO z8s39X45r_WrN0-a_^gpJ829w1kFxT{w z=xs9g(Xu}lk!0D<=1 z8y2~y2w8qwW-xQ5_p5kcSzTE`UTc(KTv>%IKSUFt(NiK*B%k;M86Y!VjElZyxvgJ$ zBcEG#+`Qpwvr&6h;yY;gbRV^VT6<&lD9B>)g=7aF<{9fbS-UUg9I~|1>`4M@)x2pOpW!=4}k#x zVqdqOepuAyJ^@?*Q7wXP3yEGGBSrBgI8&?$7EyL!|KgVm#7X-u|N79$;Tl{m&_nL8 z-vM6mj^RMg`F)x{=Ulf-u>s>==2#0uQeKn}FM{z+mnJ&V;n0(e*S4^jz3U;pV@6?Z zmXC@GNT3hEC&_J#*6Huz^C;D)?#iIXx?9~6m?=>3NCo_B`>DDWf}7$ zSd~60AIbUcV7%#5))62U4p9T_G%CNo3%>Vv!i3bGTP=HtyNlH)wIx^E9_`r$_f6nO z>vWJIa5jQpaVEnM|H-v;D+qN@kF=exqeff+@n=e#P$VtksJU-Ri~o+1jm=QByA4%SV{CxWK<8YoNNwR464WhHHBFi2 zg?Il0F=-m(@3Sx5xfymmo-uMyt$&x}aV+cju#t2(B``C;w!Xd|`gmi5Mf@&S0CT!A zYEAp>pTGCab|m}<5BqouYIKbP>9Ri8ij7GjxbEN8h>h1k#xPsoOBLzi8wHpSaszyX zaYU@Id^SjmfuRVb zk}v*(7oms?*xIPT{VGCGztJT75#m-}aq})v+6zTT`^=SHS6=Qf@@NG#j82qdb5ecC zKQS=8Z*mDV1$Q+WlY4IZDcQ}W7y#1!VBCxW>Uq3DPyHCaVWkXHRr(DHpQd3yDWA|I~FzegAyKN#s>n%ylomamN<`WKyc7N3hxi4U{_byJHVe#gV76x_i4_yMlaZ*AFEwklYbP8vKn<5WGYgl zCTOC&v*3V2d1h#~p&Ed0QI6RQQ6&9w7Vp3RNmV1WdKGm4v}(d9HGAAW#~qMyFIvYc ztKVqvUj@QhM=$=<%Pm5%%*ImNgpWNx2s8&Ge*g=Slp>~#4}VpHLjzyvbqN-9zivD1 zD0~kVK=Oj5Ysf#djF17+d0S@|FMMAe=>I))IRu5Da$V@RUu|4}*E<&k*(ln#9!CNu`%H<8ycZKfOAITZH_eqX%HGNZ}&rdVkYO781LwHoz}KI7{_>;kb#lQ-qzbs2Kzf<Qux4|q{_y>!k%4UT#jNwJW;L7`Yl^Eqz6-cJ z2z80O$DplA3B%EdwxrG-E7(3<}j zc`eeCkrmALxjOFAEeXx%ZZ4UIc3r#HfRuEIZSKokPZ;?blL~J#r=+8guKZ}Uw%-2L z7WT$8q5bSef_1V)btljY-R|Fbd2m&>95DWmlhX;PvI0bo)f#9~3#tsm5`9GH_c}Zi z#5W+oei$n-?QE%#`0(iZw=~a+a}$^KAaEEfF7>kJ!AY!EMr6JRskrCt7Fx`mz*bUZ zM_ixciAcoJK*)2e@^t|6zfrcyQ_Obs@4{wp?WGU8J?|zNdx9}TIEnry9-S^;R$gsv zUrudb9_Sp}9R9DcSv+TM4^b!|xC40{D9}`#6@?!xV6bBtZzrK^>NRpjYxjjAbT$DI&%i9c38yHG^z z-k7S`oU|&RzqKIh>lK0I^8W$R&q55x@u99`-2Hh)28yqcyKwGIA4+;ac9H4;b}B8| z9~U$unY2Y5)<6?$O%7YTRgj=p|a$i z%qg7hmYQHYl&@EEGNgWXSC1sqca{wHbkvHfClG-ynS-&k@@t5c0)S&uZPvDn!WNM^ z76j0|{S9%Cf#PX$zIjo#I=aGGF2j$XJ9$5N6lZk@V#G!t?=A{cm-{f`uk&Ju)DW@o zFP91eUzO$t3^`0qiWKF|k@K>l7Q#9du$73GqxBokq@CaxzD4ywFfD7IdGY+icbd?m zD6ZCp(cW{4%6LpRW)#o=1${ycWz_3=H6^a`Uj{Zv8-sLH-ds}**mr&?E&%9vzAMN9 zNox@xlj6~X6;J(A#NXbX8+kF5qT$~_*!Vo*Wx{swhOIva2uw^3cIc@ve$bJbB58-p z7;&V)Y^^`a^S^~CG($t8L99)|e0jWic0F(q=$o*ieWrHM(Zwg5^TWj}L6$$cg#U#B zpz4UO?QjIUc)eR>Wo!YiXh64D=C_ zu6&~qZb_;S>QG52<3L?5X^ngmbpdAv1QqbZ$zKi@o{NkMb^$?wJ}P*#FiqiS&|B_$6tgaQmxvFGO| z&udy}3;>8aj^6Y!qD|?ce^|DbKs|m+*Wv$KXDi)?{0OphC7C|uby+?mo7)A5XkdAt zE^I!AgTK`d1B@U^JtjSWwpZzg82ewXzZkHBJ|s z7<(~34H9db?4teZ=?W#2$ufzy?c*mbR3Y1Z1!amKy&Hqh=4~$b@z*9-Ta{Nw+n0TZ z*}1u+8FxsH48n{^?Y1i{HTpNl4oHxi>C4|J8nrdku?pWRhB&m>-OD|G8Gc13{7Hzi z*?ewX1R4!u9?M{mYHE-lH59^`8)%hHHdpa$ni*l#+3KCVw+C+n9>%kR_EYzJcoFI2 zioQ+g6vO9e&atyT*zjGl+Gg`@c`r?8lNhJhmvs%+1dm1Qm<+wjIdhA41u+xH;9bua z{C3)0!iM9BqpKgr3&a)j#co8fl*!KfI6oQj0l6{};`0Y@4!HfSW&}r^n$I&JS@>_@ z1Y09?%Zs)1rD2Ztpr(V6Pby==mwm5$SSwLLe~+d#jD>pxfziwme6nQZzbuM_F&LI? zir{twpB#+`8zdFDan@Ukw#wS&__WRH=AC|OSUmr8dU`z>c6z;WhT}kAueYD9afO~t z>i7m&+dQ(YxQTjKB%z$tKu;?4?oxMIek7!!zSe0t7zSg4M|g5G3WBZD8C)sK4ynQA zIaoh?nbKuKYeT)rkc8&kZ;l8tKT2DK4#G^PhF;tLW_9ZKNVopR>AFwB^?WL)U_z>t{p15nW9Wt$Vee3deELS0th4B%zd#dT=?1KvGT={L5i=( zee=!o<2AaqB5cs+m1mRqfcf;L?+f?VN}(XkrASNtkjrqniEEcimwQevbfz)I!ID5*XIMKP2pn;}vE z+|0Yt?T`ijmRpy1C|FU9uC?4SGsc0;#^n$S7s;%_NJ^EeU+*udg&yeAcce&?n8OX+ z%GJP9{__A-G~Kw}tR64|1S>uamS21V7c@-gp#6O~uc`;jTnxS3WUid@sO;uyzaHM) zd#2Yswf@f4?MYk=-)#v z;0;XfM2i}&6cUkzEaQ!hpdgk-$h(=jIS$f9F#m8yq((IeKo28*HJN^YX^X9^YCrOt2m z-V&~`Tc~#%xrsP7ZdSD@4dZ{N0_Rgsn|dIp&OF`90l1^{`sG1)b}3F}d% z|IvcH5BZwx(q8pd{Mb5)3G-Yr<9mb{*%_CDxQ+jlER@;e*w8w~zvZq_=REI14ww5yM6XFC>Y_`QNh^ zt9Mv=SRzX&_OZqPYXLsne7wxo(yY-?+o=oa{L;${-F#jooj^&!O*v$Fgh61yBM-6D z<<^;p#K#~VMig>H1@Kq|OpC#h&4>*-hwc|$GHy*{LzTFyt0`K~&)EJqDrjPCzlbbN z&`WEOYQ5h3D)I=Oj;YiW;Ma4$>+2DIF#Un98V;AMS{-{E^T)NENxYP{a;_?xSF_xM zNDk)gOGz)N`Zv@fj7{+ejdg$MFOp@mIEOYQQ6E^%V3;2x>~?qNHlB-Jv8cY`Q7)}- zz8U-a&x*nX!I*-&q1}VzC%6!;3D*#B8C|U6TD06{TtN8I23OnJNI~PA*!SNjMEB`o z5_uA?RGCuII;-IjmAxH1a&=xZr+RS-Xac)}8uD4spU!fV_#7DqdX?I$=whdJ;ETX_ z{fNBS4|;|<)ku5iun@*m=;Ox6Wrx|)2@Dlxbg0LB)UvQg_vz}4k(8)8S9%(8Vpk91 zwYeVdA7S_{$iim5KEn?KU!7N--In(maJ>4Du72AxO8KHs*5YzUeAGn8f{wz{ymf-V zr~G_)s{>OPfDFQ2vgEQ;-b4Fyq5z1yKkhrZvb_^7t@7O-3dZ5i70dA=5B7=fI4u?v zN96)b1Bf7?&CEoFo2d)#5~geJVgXD_Qpz*GGqOyh*%jipVb?s@9OUcBisY`zF`yqy zk^lgEs$YFS^yXZ?-&LFYn^;A)l=af%y3Zz5_d;ai?op0ra(u*uD2!&R-CNq- zlY}b9CW4FeR|x4EzM+eUfoFj?ElCkTrW-=544CxOa=w0wO50$n+<5XPMQ6m_2Rb%R zq!gIlI9VE$Z%8{jx-c2WB-82VwC%3ApI3Zr48Lj)# zf5K$8e-%x&(Nn?!#bz`JpO<7*`k7ec$<{$Y(;Ksw1AyhRkBvdv&a~nXEfsm6&0WLo z7S@sQ8Bozf*!eiu~ktu-SvnIV7Kt)kH8$kZy{f z0@$82q5Dw`_Z_qHfTE5lLWQs#S!i2btt?qaE{6ZCSJ; zhJnWz(EFtIp}BGfD(%NBOm0(F8%lYlsqRWe(WVq|?R2bPhwXu+6;Q48BiJ9CM`AL5 zF!x~^eW-1t{Cb*aSL}MM{e-Ul%GCtB=VG?aDH@dw`F2ZBFivo5E_mD66f1LwGAgK9 za-++hSXZuTupLH^%=`7*T87lS#+=t`Zm=iTQ^w{AJn#jGjN~Stivkq0!KC8RBxF1o zV)k**AmVLV4=>7=@I*2R@GT|3ACsq}!>(FD0$l2e2II3a5I6k07vC!@0yKk0G@cPJ zCpT*vw%fidU(IdpUHld-2Jc=5>E>x75Dfd^aJSaUdLW`9$KV^mClm7C%yDpN4=%FY zvGn9;w|9G1g@ui=_EgK^BneWNZEos zO#8?wt;_~O(vLFXeT`3gJs4hG!1uJ}DLh7Q0o`P#BY2atTCh!6joCTJ%$&0F2d;4X z4wyY;$bYLa^Qf%Ru7_~1vxqwUjpyB=5 z5u0wY5eFiTlzS{aN!h_33{BXGi0WkNdSfF>hx8+Cju!1Ni*M6!dpjhD25yF*zx8;% zZGa0z5M>Kn#LjkitB0JGhlwZvPg*F(Im1Z#az;}?ZS?fE1eqo%qw#Q4e3KOR{$WJZ z|Iu_E?rgqcH$sW=Be6=0M#O4q&8j`Bh%Ho!nl*}|wfAaNs2O{Y8Z}}^tf;C|yEUR# zR9m!-ReMzX<@>Jd`w!mheV_M!?)#i`pYxxEDXCvu*vRG>SDeqlic69&TUFqqlk(By ze7lSJl7Lr8mGb$JAY7F5sFn1~U7z742qc(*shIDfjizBwxCee~%C@YkveF)qFG4w5 z$gnlDV3G|zJGyKaKAC;IrXEppnkCgMZPYCu5ghe%``$EY1XeK`h#14)=jK8zvp_6- z=^iggOP9Gx3Jih}8Da4lybl^gBhFP8WBvuCE-6a*MYB4Nb2Ias%wHZ~k{DY8H640D zmd9vtjlw%NJ2_iZ^~b%8Or;$P0Bt7?hbupjg4rMkLHLJq?&gM#x`KCI^(Jhx*f)L= z_hTY|x<#(0_8xxi&UV@t4e7F{994{+W7Rsk-{irSMnC1U)V%z3gbeWWv)i0UKSZz|BF5MtB!bTgA z*+S^`dcKV5AsKkhmMcqXyA6LU(x`xsFNXry5df&*bD>vFEl}A_*CG!7^*Zc^`o#~~ z%%StGGYJ7SV0U+SoZxeGji_`jXUjw3M)C)NBur(4HQHK8Lpz-lN^c~xabxEOROR9J z{npN+?DKcqym48&cRxRR^25@^y6W9F3J&>Q7=(C9+fq?!4=cSVd#xKj+ir}apG*zfU~8zB7(3pOba#pdSlK*C_r85IPEP`>^N>|mP-OjUFL3JJX$r=w?Z~bT z^BT;^41ik6GWh8A+&ULGvCh!TpF&rBP%Jx zX&r<{JLtFJ^X0q_WwIhD_`^g!fk7AsLS43!;|N2}UnZ(<9^Ip6ijy*`cfu*>j5J!s zk$b~)rp*`?34GpVBPuh@gAx!4MZYSe)0krU6y5R^CIwhJ%h%>>>XK$Oh&?G2Nmx1AJ@*Nrwq3`6H&4&&6f~bjlMHh~ z&0$i03On1vYoCOM-7l|#Zk8inmJ9h(uEK!eG!Xrtn+eH`} zC$XTa5WAbzgyJO_uV2W=cm^Udpun2%VXv;YiKykMHh(v@9A9i7u)ILH9@l`lVgx zdB@~WbqaP7Z<4=?_Nu*NSdBVl`}e6NoHAy~9cbfr(bM<97K(Y02?AmluoP$>b5Tl8}pzf-&<0GCUwYbaefL=j@q7Yt>1hoq(4E; zkL#!6a>sA}9fYlOr0pm!Z%@S^i?V^s&-X+0-6^-v!qCwJ=JSF;!MnM7(w>kA^{ol~ z_7vypZ6pP}tPFYhs}ci%K?+ju(6a>jiL!vgLPEShCFoT)fgzsxU=8@)4t9+@209h4 zcfC1A1Fziq4XZigc0lXh5u5yW^n$41dedd0JuYq~%(v1I_L2Bq?%(S9%JQ|pfmwU{ z{72%gUxpfu^Zj6UHe1{MZFpDKjCI^x=O#@oLTpSZ_dW5({?xBbCPCoIdU4(h$A)~t z;A`eq81EMYySc>_DyZ<6E+GMw?wg;Ghl%58jSXW@_|ZRt6*Rn;JKbVC)?VLP0R-9D z`d%?J(kle8^h3;eus?qODIFo4v+!uCWi8Komc02#BQ@-^T<}&mQLb|M)k+DW?p;;^ zBM=}vic(-($#M6(imb?#ccE~>0P{qe<`7P!gU8;Cp>5+&HRxPobr;8S+vrWv9Q{1W z_Ggz8KrYw)^o3!_;#|5OS#;R7@)6Kv4HV1J9>~qEqxF=*)J#i?Swxr~17P9iOh5E3 z+>jXY8x)l_`%thG@tYw5PW58_L(T6xyd~K_yDD<2aAXW~505e_-w2>dde=tr21B*V zwfa`CesTDR#P=Hbp%w3F<>K)-L49aXA9SBwhYA?HtkRz;-w$xd3xGx*?ip&Y7vY`9 zdFUO{nqZY(!*7JDnT5{BmN2Jn@{mw`A4YRP53@r5{Y8#7<5p-+gUEf!fAg0kf3}Kb z@E-E2g5Dghj^+eKb(LUi$+ow(T|qA1>q#9)0s!;Su`7m2iaVhzUw+qU!8I|Xp(u({ zPTtcyj`+i@dys^L#iu#CESU+XdhA1^z9n*OZ6)3BcP~8xW3Bh20fgR=6Bp$=I2wv{ z)fvDYyL2uZDQH=o(`&Fy6#C|c)k*M?TlZS(8*Pmg)%crDiFe*_k&E7aEs4& zQ||9!xSn{&NS%CYl-;R!i13quIx1F5F1;fCrkvQQhWP{L) zE_)Dvx)nMvuagi!SPWY{GDj_-m?lqu6&?5PdYykcCPn@8`B%Mivht4~2Ku_#sH%E% z@#551Z0&a}YafQ&4k^83ohb|fM*rt~c0$184zsOz$__>9@sixd_bvANuBE~=23Vd4 zF!Bgc8_N)p3P*NfC%!E`AC-E+cADXZY%d!~Gr{HhgCr0r;c;<;YWcDBJimpFT;rGr zIrlX@GLZNvxqOe@O87Vb=Fd*#KB4#EdG^kByHIk7vydod;$x9S{QmBy9Q#_W+RCgtxp^a@j2W&P}Wcd0B+IqI0p^S=M2=)*4wCbX3%6MQs&*arr4gHLj zR8L>AMSkJ`aU<%;h;nQAU6Y%o5r?2;fGy=!gqFNutm39GBY;~N+Amo2UNBF*_FKk5 zJ8P;oyKw)vP=SRnLqR}{w>-1x>H_5{lWluEEP+v#Ud9IW;z^G*B6xonYE79sA1U-8 zLS?`lz^(w02%X0Bx7Va#+wIb_%(GpfZy9%cm+fz8=2I7BZ%jsgME-G}b31_2MMquK z{rf%|b;MAzxTAcsf4(27AnDnyY`>1(u*eT^jLek4CUJtIo1SWcxkawmz{f`t!3MUH zRHpYUiPAJ0c2XzTat$MHGy#R&#h4f+YLMbz*3s6W-}&f?_x#b-9h z?%K7mW-tH?)k1{SjQ0n*Xbotv!yvebyQROYQo-i=m?j$orOxATzUn_K%GZqtp7Wc_ zC4VAz{&(tboZ;)S?urX?TSv5dII$n6z|n0pFApUvLyR*Hxdf%^J8vx_T>9#11*M`f zF(2!@gPihx6$N%c-{uc9WmT8$4V3=;CY-TZ$FKas-CBNlZLZQ}%wRciTB4lTzMu?~ zLI#ygwYB3aS`Jgb42Y{>zP1!+@j~K4zP#0z;UE|798vKC#U)zzx~r|P)6xcVfk2%O zeSLRtVtxqa1t3wZ9Q5izvSD~lj*Dt#+YK09g9M$~a?T+OX1O27W>?giP-|o2q7{pn zEw|-bcDc8w!1|yiYM;t#zS+N<{q;Sf{cm%avqn4s3b!S_Y*KreB7B*SbG&-=_u1LJ za7T!>&n_EyJuJ&FYluy~=Qg5??z0 z)s*~w?-Q}NoLII~AGP23_wZWO1!3D{bh_~7i|bErdM;x#zpV+@fn~t&;i8i zxmRN`@cwvMjm>CCHLag$Lc;C3_1kNzus{U>y9k7rcR3dApxt9m&dQW$J$L(ea_#Tj zn`7OQvLBT@^^@D0Cs{r!lc(F;Eu7y)=ae_#~;Sp)VWFM|jGhjM--GV*B!W*e*&w&qE=VNnj7}jxLJD9Y z@o{;^;RuX$TT_ZcX^;Gi6RmjKJF~ocs2-LV`Tg?ueUr}jYv0aC$GY-%MlATl=wRLW zPQzuxX=6p2uH&v*S%4RgQ7N6plr{KTW(M3kIEgIj;DG+ovsA+!Ek%IzTw0Bm(PCZB z2WPnt4G2K7u)bKkr6`NAfYf@WjZT{z?sk;gF+9G^#XG{>jN8dl8~7AtDy-cdc8B=v zKHqu6rZ?N%n}5mIK3~6fSlJkP;rlmuhDLArJ4h`6TF(3>@YXU8IX-{i?OOIIO+T}-oH7k>&A`XX(8)p|}n z-<-Rt@70_jaMZ&M0xTDE2hV~-x2)f58IQ*43EZr9d!VpgT8oaxj9)3W+0iJk9}V5M z^t-N=KmFZXK>A9t&|Z~I>eH_?q5KcTT3-wZ)n)5}ozR3!P8~i0?nL{X?_^~DP_JUX z;`*R=k{~t9)rvNlVlX999`g|uC&jX2)Cnq_8||KC6?vBBHZix-QxI8Ld9qmYrc-@6 zfDKrKqy6YAS$VqZJAnm*6a4Z~jROm3>oEv7?RsLD4HgYJKXuLJ)1g7f7bv4?#i5{d zy-r%CWMhqv30^`LC&B{tUyq z-CBE{-<3YP`g|b4yPAJ}apm7&sxXuK<{bLu_s>Xf5%yLA?f8qW57vg|2xb7w&Xt5% z8{=;8!=B;{5fLQmB3u^E{>n`c;HAQj(SQlH0pGt$jYt!-U@uD&gE>DtCS`X|-vEk@ zh;L;FK-Lw<_1Z`{8?Gz*LPN~p;OBuv4mF}+Ihz%c= zf6@oPgDCI=fHz*=Wg&EPol;3^7P{qSAb~h+DMsceWZn4>$|}23Vs9Mcihg?uX8DrG z@G0Gs=Sv2l5492>Fh73Zx%;0K*LwiWX+R(aKx`ZhRlBuuH(PvXaxpa5^)&O$lN|SW z=|jQQjvN(R(l-lN0xKP+lx6iII6OF1%tuuf5dZanS^fA%)ZTb%)OY05P_GgyJb6Pf zmZ52^a;a$II+H_xi+2tUPm4zRvt;JBs?-p-ZP|QX=S?+BJR2Ez5X8p;5fCZjh`*AX&+3A?klGe zq_YmOzG=OS6P<(p-rl0vUwj{05Q{`oWFx@9zU6mA`DfzVp0FCAgDg0` zu%(6F5iq+YAtChn{WUYzV)%b;_ccI}bmwt!g#JEQ_X#O?mKZkh_=Y@%NNBnONS&$F zsA%){96rxHf)u5B+B4`gCFG)|)-(CbzB58RY|W8Di#vhV4kMwmqmGtF!T0wlCFhIR zRR2MOO3h066tm2ID6JKB$2FXiq2>^UTavguvB_VYFq9aTJ;Ji&r`@qlF zbhL1meFtwhekL`>W4aTeu$8e6u%g6S=iUKhJ}k3N_df1w3;k>#6Bcwsn8OL7BF^-- zwZIpDL%!>~sQtg)_`~=&t)VL7d%uEfOsbqqagvHgLjeJ;nQs19`zYS{!<1;6U2(Jg z?5&=X1|gOhdgV-jYPofRIdA}gTn$jJd)&&Z9X&%7N)Ms?vd~T3HHZ(H|w zY6(7NgrhyjkmKRi4pJsIQDQM$n8pQYo{f6|YJKV|%|;kOn~&fL;#=U-0`X@AeLYVb zRVT|!6~F19T3>7VUfEC~uGi%i4bY5!7#2`xy+N+)>>P^h`YAB9zZ@AP+alVsPAbqx zYKgd}qaWfFR+hSI>7oy-Uah9IdsCDfcPxGUdh^LAaT~YPZ4B`{wUcL>xg(w*?Nr_r z`WV>R6#3dogi^$ZYf!G7u9QWRM8Bu!`7-YKejZJ%-q`gF5i{U(3~sKxrhqLgicJH} z3RlWIqABOgCu$ddv5mqy6geUc@;F zV5Z)7vKwP5Gl`foRv-kepT4v|iTk%(dF`V8eCt0UE-B<+>bNsisB(F&N1Bi&#LOaQ6^u&NX5=8}&f2EB}9W zu!r=i+=kYauKJaG8cT{o0PglXNG02QUhH0KC4+ zQ>7&o&UdXSWniFy&Fkrt08gUiVkPNii@^Ft!)9$>Cq!C0=$J%U=zgsP6w*e2d^#T8 z0*7cHU@Q_lX@Oec7#V6)Jc*Sf_spA&?W;t5`+Icj@X{%RefY-dyU}k`OmC;WDqh%% zHn?IF4~?ub<^-K+y_w|~ulJ;`^&alo_{|IYc1TZ$C~l9irn$>e*QhOoOQ_CEw_6uH zy#jEfU6P0cDgJdNi*xWJs{x^utsy^ zZo~L~;nl;!)PVW%#we=WW@P|blH)nGnu0n$Z+6G zuoKL+|MJk~bCrUjlfs;?&1!xiOkB&M1C!m>-IhOEc8Id^Bzk$-w2u~!_VOi)Fw}U_ z3=}4Y;G0~OC#U5Nip|LjiGY4i@Hd%piS9y#bABMi(Um&?bt9_Ljmu*uL4Hlw0vn^Y z3QF#c4g`_hE~so{+MM_P>FJtWE1fT5iI0;nH>a!YICEovFRcQ~4mIF`h#-g$W^2L} zb_ArsYyx8C+v}?%i5RMkG}_toa=Nptp-Mk*b{8ndCSV7_9+Q>1p`z?y?81YNi%0Se z8Y_Jltz`tXlb3&GW{6nC)FJh>7!%HwO}zhIJm^h*{x^Q^^2!L?=-PG|)5tJld{{6uUn2HwNqu$4nr75?Ro2+sG_H$(5&UuRk_R*TqY>uvta z^X9_-_2}7eo4JtX!pGWOLm{@uh-#UuY51-JHg17!DkjTlHO0PqZ@r;ELO_o@;6bl|Ex;pP~^fbffzuF8-n^=Y(3zcx0Ihnwsk9l85^zG>H$6}+(} zQ4XSKxtGbfp1=`;2!A4U%Rlu0wE&buHIq5@^H0n6-lOM(%yksql!<5`^-iYanhJw0 zCQWoLZQ?lH+k6#`Ja!;#hWxVXo9{x-JWL8!4O~@)^)D}g?`i@vy5uV?7DptOiy-&0 zA+&IoM@dgNbg4>FM5&aMPhFyzsE%_vNYp9SRI+*t1E6!=whqaW7w_%pKL2WCVr4$O z=JR(+{o)my+8=4|FO!s4=AA_*x3(wl{qRuG)E+)}#ndUqW7_7jHo`+2Gl5Ta0cfaUHkQ~9a*o9BKdUF(({%=ogmckrDi8k&zu{AlIhnsx&ijlG<1gTFzdRaRz<77J;7JRPimR)d-V3u=Eq|N>V6$nz2QMML z1Pg`YHarF^Xv8GUdr^da$Dq-QWld{p(1#_TPB-SU*Kj`i!?NxVen9}XJAeTAvFe8q z9?kR%E--NYZ9Tlys2{mE{crQa=R&yQ`75x)5xC{t0a^?HV(+;_e|*%H zyH^-rOVDZSX#-Yq1<&`PFV(6(K{k_ARz2FFS4v?6*-Y-=feA(9hg7lRN4((a0nHw)SzFux|e# zL7o16U(R93mrOC1(qp?i#ZMnT>+kz_dsQ#{yFk{XcONUkp&AYY_y_&c6-+RvuQ5oW zXi%7y$(W2&YQK%;!gxLiAzkU)BN2aLV}DArKU)R??hqr*Q#>iW?*L$}`|9DpW7E=u ze?-9emfL${0%T>64Qvgr`&}R3{2Lz6BPAosNV25qJm!WQfsD{)t&&3X*l()R>P-v9C8uK+jm&2zJIQpU|EDinQ*DH(rqgzQM<3pAm(mjf>S$_zpTKR6QR64s(S7E$rN?eLTbtZ4;adS?<~ zejn%$Iu0c+y1aLb-y0l%!s7GLe!1s(^jgH9UqdIeQT>!gHZ4H(3k9vA^Xa`-6V}FT zeD^i|)7`bY#Sm8NnHVFjaZ1JJw8yVK#ErYKL9_whLu;?G3x^2Lkol^#-kiurZLIt|n)~NrKwToBvnMwmF3)+VZtNExuAh0#w@bTb^ zL}1xAON&SIx;Bk7MEfgAeh2LM__;Z<^`_x^?`Rw_KS&TZ@Km&%oHGEgFF_inL-_mN z(LhYCf^Ty42ND;Bj^I4s&GozaRp;OQPJYn+Wss8h@__pUgH zOkSP`%oU)qKH4(TeRVelv~k!nEAMVBfiO3&3==Jfa{vn|$SHJYZ2%QIF<6V{v2H!A zt#!@T#`sq&$yFE*3<$v_#W*!FFQWPcb3f87=ihz!Yp~)&MdG~>_2JBu(8kKK$sK!D z;>FTV__v`VY~+K8-LHRAsm#;pT6k|g)$cg` zl2!J(JWJ=TUD)QogSk@~TS4RCT|P}xhIwrvN91A7pU8DG1aek0gI(5eee!Xi;D}_6 z9Gmd>^dATz1s>X-PQi|QV&)2diuv$LwcD?W1e%b(E3m5y3Dnx568 zgMSs@@gzdoohp2PY{BZuH_CJI7yh8S+Mg{rDxLTT2zb&iQ%oFyTt-b=Tz;fT%Tu)j#6l)(~LT22G%P?6Jn9XQfI(tp)FJ z$8nHJicF=}2dy#q_-!qwzW7mhh4ImL!%mj3vRY3_aUbees1mV;eU-aU{Dw#9cuX2Z zoWhUiJqiCVhwbn>Z{!sv6#0>NNlVd9d$R)86qKi-@~(=}vh_QbFCh zz%0U_(VPFCoyOPw(T#dCm+gtyY!AdwWfM^dAu}PP;#Je{Qf#yUSUmm5)2drNt0zN2 zZ^GV$b!)~#fx~ZW1e!hpJkBD{sEGJMF@d{nefxZH<f~t1qu5I zn?Z_`P*UBY6)BD55nw*M$lr&Swm@NoE5UefajW4`60KzAK{0Ckw(bF#x5JMa#o%2hA#h>0bmwEam z*>B7agjfqRym!hE#$!oWBtHN^;(Ddvo2(Vt6o*(FB0*YWAt+Jd!oQn6||SPPmi`tz*;*X5wP z`qs{$bMJJp!rHKg@#x9Q8L~@Jq^L!{Dc8G7K%ugMmSBs9^A1>WI713U!v_eZmKhwu z?jJ!v@Hz9&#=pcWiPKx6&KtiFF~jl42Od z$gth9O(KbgQ4pZwCzO<+z1_*HGsr6_kKNtm;lZFS#L#Yy7M~3=LL)4%Z|ybcZWYRk zc(unv+ohFxFkF=KjmV$bvN zp(XCrQ&okfvkSt?H@lfQ%<6p6^xp$ySQodeb@7^Ot-vMC&n8n&+^^<#q?@3&68zpe z&!G47s}DQ23puWf1zx*cd0hi4h^a{HDybYl<70H$E7l#^=L35<{)d1uYOu@va8n&x zLWGhkV-f*UX;>N_>0w!Mv0)BfwKQbBJ|fW{`hhw2P8$7Q&1+K7Rzc9xDY3*3cz2~W ztZUI`G-+ijF++|j1COOffn3*Ko!6{q=|rT?{+SZr-TwQXNoT^gXLWiy0ZuYWeNFcY?YFh|QTUL!-% z;*b6q-O&?ybNE~!K;1U=Ii}R=fn*UOZ@4fhx?{>GY@^@w5>tU0k4L5aU>P!IZ2Iq$ z8%n)O=Wp*jmEi=s)FSr}`U7m*c{~%>Ogo!3!AIC)X%QAr&`pAI^et~)F~PgS$*u5A z=w{W06QYU03sVYYsn2X7GxN@rcey=~o9QOr7i>hAVF!FnJW}WyY(*iA~ zr>##L%z*xaA83$vtoSD7@H8Fhz$!<2B;5ZxqwU?}$g+svT(PMo4~6=r5f}bK9wjzE zU+BX$ZjENb#q|*HSyK$_*%()UgT zLd@Y7_^RXB=Dq}Dg_OvaND*oVI-oNH?bpFs8*;)$?!I-;ey$-bOoOPoY9^-lSP~x_ zs*!X@c@g+%r}OWN9lj3df^Xeb&2BI6bhdN_9fwyhj!QBFHf&3uFDVJT@Oa?3Y?uMj zVrk`2*Bzb@pH-yA8C`H(NEjo91;*~gGb58xWvyUZ)*K?{B1Q`coL~fwK6PFD?jP|2 z{HlrjQaTc4kTuUj9c`KwA2q9^U7((hcLgcYkHisOP%!TGws?2c6d#y`6v$wZ+_9dl4@`N5Qm}T z3Nz2L7<5J~Fg_2(`d5{Q{@#NDl{didxNe!{T-Jb!=b@6Im-lIlBe0^K23e+xJR6e1 zsbUtt17$l=)V=4A!OPjFc~!-4R{bXb{HQblzE@^mUyZPtY|oiDlbq6b@W%P2r1gx~ zKiVk_5E*aLxb$Ahon8damR3+dw?n5X5vQZIp^Dflaygpd1?&(v=DQ4l6fa$p~O(qEtjHIV`?xJTcNdK#Fu{9%SAtp z+x@VYVh~FU;IqANvP2F&+7eP;ca8hvbjhjMMX#KD$UQ%JlDx2_=-M<9d{i6*iixN5C!^eWbHSHBSy<@?qQqQXbp(Z+&FSn0;b_j+(6oN(F!aoK zKyS%05egTosqZ zOp7}_yUl3r3am==ZIf0zvHRJ_kUI+Q&FNfyS3L^}hp*RrxX=IxqUJ8iWsLm%5m+C~ zjU0ipywY>me9c8iClDc-*if=EHN3z^-uo!qXg4x3^xJRvZqRZQNiE2=GitwKUhbHz zT;P_X$nspyh*v{=ji*NetL@tIHBi?ZsVUQdr;EP&P|(G7!f2a@NSIg$IXn>%ckxy88e}_8bF%l#WC0ST0&fOn1^hXiEa(ueObx(5|yd6!os?EhoDw>mv+i} zWB7jjEjul-l$)owmhqG#zv@qpbr3L(;vuZX#W?Xi4XBCqEnWN1&*ttHn}l~a`VOG)6W8hc#i~f(FP|-l0v=%fOE($H zGgg7&|k9!h=3z{5P4ok=a8fA0I`a~~L zj`2v4Se#g3IN0f}TXKhMz4QdMtXYv=IvCNf^kD4Jy+%bAX6^Q$vKCCxxw+t_Dc0(t zeX;k1v&bb83A=F7>I&^Ca%D_~6gJ=zxj^G(UQMu@>gN3B;1(fbV;pag@~*kn{g>-@ zj~SmzZ(Gm?3$4EJ!(v%eK3&Jsmm8NDE5T_MHB>K_Y{8i_Eq^l4Mw%X%k81e?E$&IX zL??-UYkIlO`cVu<&qLg~+4f5Gba zk=1;_$%)9VTag-yPf6kH*+tb0ZdkQRqe}vxUxB}HmC1+jaQg^7PfH{|I(pwdE=DW( z+|EZh=>3gHK>9}E=*+G;`y1Kig36Ogu-(lwYm+pn;4d=?Dgo4|yi?!myDP%Y-jd1V zUK!g317$Vn>g&CBPygIAo77O?HLDeTcp&^5V|Ni zr})B!+{}Bs8V&tb6-KnirLxSr3juBp9gP0Z^2*Eff*Q@@A31mKl(Qs_R$5%BxX{B` zGW)+OafPvw|0`y8f$JI7wsFS(`egC?e*LQ#^z8K@O7hb#h0x`_uIXv5i?Kkg49u*$ktlt4!-g!UXw$@j=0`h4v)7?oJ4tEm zkiva^cTN=IUSBMR+Bz|5x#r~8mk2-O3_ACm$h(7yA;JW~D!`^=OnN_x2e4417a!v> z^Dbg>qd@-G)$sjI7YY9ZL%*FswP4@VqpJj*|C#xJu z6c?W`9oaqpRu2a~2Q%U=-Wve5f6!F2%Ey3#(G*8peet;6Ct!DXFX1E)qO)q|6fi9C z2M!C&jmfJhsGW_Ch6yKxmuh#%kvL4WPSy& zpovTRdhPm%d#}?nBxvYrp4XuG5in$(v@pg@ER81Yve-TJ#G3x~$qA*pEUl^cswz;d z)?9fPwEykRTUPFkLuPF)y-T3G?^r*{1lKsft`K=zI0LMN4*_|7ZP^HhLu|Hhh?Hev z30mscHaNERT^>%ev*R2!a~Vsp_SV{^4R<>BR= zSWMegF@JEQKSobqw-zK8G4cA!Gut#MovSEXsk>cnF5hljf|(jV=4y%rnLS)|al`6V zR7P9*@;ULL{bZ9D1IOUTy}m6Wr=@q=;D5U(SN<%0nx=cgd!^Ze91MqAv(cG-x*D_e zS%MogCz|Gf=QqGCP!NJ1sdt_GDpQt?IkRVsg+A>017wk{O@2Y~ z*3n$0X|zBzLgV#wEv_O${?pp3=K#+#3)Cbj_Vo*;rK6+Ro^aFfinS|{;s?%B{}QeS z7NV3PBTqN7UqIPKT8o8*!P3JrFsOK%?W<2zsh8k&BkdU03M^^f>3Qj~KpK695Lu>) z0gPl%fKx(t&@(8CSW?d7s2P|+zv?!vvv>vcBNol%kv` zdz-`7n_47(S#*@RQ0-k1b~Jv`O&AkLcW_^E3*aFEYvP_hp~b1vGLB%4g&M5k%mW|D z=S$z=TwzC>Sxoh^dj0d9Z)r*oZ>L;g{hZGU$+XZPi6l+7c;nR8=9vU(HBrpbZ}-39 zP)2$dv7QT;M=jMt&W#dwuGx|QE>L{zy~WN>$1;N2dd~;nqIlB5xSyYSJyi{a>6~7X zcgY9S^}*hDpj7}MZai$f=BJ#I9>~?%p`zS@zAu|bW#2&*oN}{Pm&f8S|gRBt(u8c)G%xfr;zgCJCnv#4J_u(lIfq5$9o@X zQ*TQ0+juvEbdzgzN}&k9$@-5BnqtC?f*vRal&JOgd}YWl8j4xb%Q>Za4g}|SV(SF^ zS-FTIT}%pH?0(;e!S$MEB~ZOQnO88*&l1R>uc!H*!xiLR3%O03zK8}V1b2Pnj44_^ zjhkboVwBJ9sO4)%#BEUxFWbG*dZC-`v!wP7LC?-j>N0-@_QYi|(I&vBDpCiu*%S3k z5$P6^DVZeg?>&?IECBpKj66N?7kn>(^=GCka`SNMh3A+8q{ zu=Y$9e(&+5JggJ&VVqgvXG$pwT_LRBGETWgi#heeZGP^rof(mxoXwK9bmyhNE=K+; z#6%}9o}hh;I^{44R@qGV)n~d^s2I>hry)3bp;&Npb|3l9tIXOs8fg2u=i%#yEQtmd z>OjVw*%4lA>4~q3Hj*8%GJA1HeeP`FP@u*JI)!{Rm~J7&1YN8+DeJ%n(gcHI-m`D(F$h>Ou{`I2 zC=Dw?E_Y|gv6mq?i?~bMQt%$6S83s@+HhWNkIC#BOUZh9@6)$$x4E8|XW%1OdryNV z8g#Hp@kRSakH%5mCYzpSePgVTT_W(1OEvO`D1HE!8FAisg3|=Z`-n(DiEGTD7}+&o zrm+}0ElwT%OX!{^{}%4sp!qwxU)nNJ%yg#uv+p!Og|%_mJ4{a4-5-(oQK-nj<7D2laodl=t~B`Uy!Gb`XlFxR<>#p$I*=eXooMN>Vb_zu``NMn-Eo zKgq62n7RVUME0q%JdzY{lD{nq)a0bsRIoLfj(lbJXa^!F@oR!kADgM=o}ZT}r-U`F z8=6i&8(+Kv{}bc4Xj0NS7`r1fhuI~%G;^#(jgHmDr-IT1o(&lixl7$Z?*OXtF-&d# z6Yf;dPnS0?hMn_q+@@avqF7_cO=a6gut29{-aY&gN8g_0UQ>oGb))?iB!>m9XFrEGl z!6YN0doj*Bxy2rBzvRKDujEpiN;)N5W%tM3V=gYI%$n4H;u>5%xbCKckLY^Skqvqw z#rmskQ{*RV4jl{0OEdl8WPXKK2+H)9>=sg+HG&Pqkq*d)M&qagt^%z}@Zh|}WGKQu zo%(wlzYm}TWtt+z4ibhdz|T01OiaWX9s6SXUR#>WHwP^S#vgqBz3{v8#!zfrPXs;7 z1kal$(pJWMOVyOSG82Ky#84=X@Ls4b*;Fu0JdW0%EabrXeuMk+SFxwJ8)vK2qVssI z*p+sA{7|E7vwkt?nTqj_JeLSwj0O|n79(!bX55vNA*6USKRIhaEX_QC=-Ez+%Tu^% zGWutE?O|i&Tyl9)?tA=A!OkTfpHKvMye9l@t3t8Rz3F6X9vBK2q|5^TQTkcsW+mvI zDHCuv`bW_{EiK5481U4Y%4C-#nCq5Fn2&kJB`jUJX$$vjDbr^9II)UcFA@Qr2+Lmm zud%3OK-T}7!Q1nls9zpYY}a`6>aN*6-1aKTPtcmh%0&<=6hFe2%5HVYcIe^9^Ur$^>2#@xd9YdL{ViTMHZxPAo@jqSvW9%`x zKVTke`QkfA6eWeE!1lT>nQlx+m(+EkXq!q&4|2ul9CcaCrjX7;JT%kNVu6*FrZ2a= z)eY(cti9W&p78)d?C*D(uRMZ;d)M#V-C&IVV&vqTFq72AsZB*b+t^u7$y>>?2E^Cg zlO~f-JdJ}||N7}R_)dOH;h!I_j5|CeAGWsYzpYt2^0@V%-puo+qP2-oeiCuKyeV7p z4QVTwLi1Keu3zVtQ3YI_3$iA{hPI*vRC0dEEl^3zRJ^7S0kOP;?zdL~=}A*z?dFH2 zIr-}rxUwsL0S!i5=SL=ure0sd_v}?~AC42qYJ|_sarJR;6W*_hfs*d|4wf3WEZqTR z!Pp}**7EM_bEF4NNQVN1cy$7bKt00g>v{hl}m;7jDbJtj_5j`nL%5?Qc;_kp6&pPg2$&k^}F zX5Rd?v+o>;CENv}Nz#KT035he|L9=iu^=dY{hzU{(P*L;O}=a63c>db%L zga-d#`!{_zSc^{m&QlAQ=JNx`zK_=&s)bl6ao(h@=^{#i z<}Rk=vv<6skvNSWu;*~%iY_`GcI(4afdr`O()RI2wUg#s(oc8z%GTo6qHD2o^n z>3;|%E59Gy>h*OEAkrmL6QKZ5076^SLO|?@M?ai$@-=zUtu2#S-{HtW3XSPl+B%l$ z#?6AY=#XoJ!Rvk$PdthP3;|KE`R%-{(onvts%rcm_b)u?Qp?soE!bT39 z)(<+YHBCH|qCb^VP5~MI$t$2!-l&q!b3! zqnjp*f7V~#xr6eAd`7*>JR&n|;|B7wvbS6XW$mn_1(LzVz0RC1mCWP?&XQH)*_oAqmAO8pw3I2{WdSPDmowND|r^`(v`U8 z(K@689lB;86Bfk+B&Ry1WA&IUk%e|Bcl_5aoO=RDn{Bi3bb3x*JMztSw(SD-$g|3< z*){=~Mju&%psX+^hqD-L-tS$Wq?FyBxZJqV5Xin0!T0OXj^NXy6C;L7hMG)6)099s z7qFeo`b{?n;Rx3Q+wP6$8ilA$uM(f$r!|cRcGpigQYSB}AFNne*?G-=J3>WCO4FP! z`^kEJgGdc0LoJX8=0aJ&{6n?1K&UNYa@dBgkOzAw3Je0$1GI;3PWlNdvc5BZ6LjH! z_eZ{Th>`BxPNA)p*S~{WCM(q?FhqG5X)- zm(Gm$uvL9ePYyaeJFVTGc-yveXJ`nEnaYgHaG_JYT+f<8-}Krt+PLCbiuJVduLV66 zCay~dtk|pm8=O@;Sl_F(+23HjW_0dURhEEu2>QOs6kS;4eH6wBOHUiLK8g&%XINdM z&ricQAj+k{ozkepNUT^T9!4*uce`B7kA6=srOhoZCdD(EAGba=_4DF}a^q2gI+pr5 z)zkj;i|!8TruaWd21D;PP5qp0drF#6@Tlv=&3P8tC2khEak3{Awvt-|$UIlwe*&_0 z`=IF>rumhcVjBgrs^5YpXQ-xuyIrU1XT#@_T0d$(kR_|RAGBr}M;(*gGv*^-?8~e4 zF5T6t4A_21$QXQ<>uQbThCT9@kV5TL5MIOLSQ+CikY78q@M4*ZC_ghk=C%*v$J_IF z>$Y-IBK0mJ?+Zj7^xkc}2qAd-J!+q9>q4xjqZQng5n{CbFP800K%Cn8n6ancw)uHd z77j&@ma#y|fZs{i-9olGKRxja4XZ0o7rN08epi$lzQK^Qm;c8F8?iVU_d2E6b~w4D zCZ0GJ7qfF{R3VqvMhc;)M0giIOGh zm>$n3Y=_0GT{)(ST;q6aAZjdNgG$VNLYMBwis269zsJs}FPSIkx3mps0dvcK2I*hl z;DbCe)4S&;adkre#MY+W`iS=&^vZVML#goJ{@l&;gOmS*Xe-lokLnMT)t+wFGsto= z6k8()9Gnu|=9Hr=oPV!Bc@4&nY3H{r$^UXB?GmKSz5=rY|s)u`cAe!5u$f!Ptoj6)B-kIjF z%C5K=vF~?fSH0J%;i&nhj#{e;pYYH9tyx)#>IcNKW{Y<@g2cOhSi_afEKOXxQ65W zfT9gcea0`c%!wez&F4*&!?sBg~8%Uaa!isZoNndJV^Wy|f{M&UWtv#}M`Fnnr& z^qwD~|D~HrTHTsAFAlZks;@6uR?_8Kp$e1IOF(#grf-T2+B^}hF;&y9q);6|ZH(?P z4aD4Kwh#Tn;c2~LqfT7VJ+t~C59=A&`^=B`Ghpaqtj<&H#?tA7&rU5r|MXKOU5shR zIB!TQGk18^CII2SG3;LU>QiPbRm{cQUF z6Zri(d2u1ct#aAK$XIV0@1To29Op1-%{u$UAO<--#qiftNq?%V#%xBu#Df7h2qzV?NuPV8T3pIcAXd#0P&#QN0v)I$y!A%#Stkg*Et zQ8Znf*)e31!a98FAz{#nA&O9lSm|02O~uXm z)^)dR|Led1%d7oeUl#f56HlEyu&{o1J#F{%ZswB0Q845T5sHCz=%60P)AgC1v-|Ge z{_pGhiGz55B-*0tx~|Kms9v z2&4j~A&PITPw$?){gJ(Y`L`c!4|vD+dzTKM>7Hn3oy0(HODGtaVX#T7&<6lS00JT) z0wF;u&_N@rU)P+wY1J+SAQ?|kEGpXOsC*NE_g%GW;sKpSo@O`ulEr{_P)Kt#e(3JaEe+$6r3Y{?>8|{Twm_ z)`4^289W1f;Gy3yKEVZPNdbL%M-!M-asd!W<4;_RS8ghMVYekH)-(J}%ez(UbAC=Fp9 znp-}#;|ss_z#snWKe-AgyfFFQ-}(Bt{`mQG&n@(zokM28Sa1$};rIOp3m+zfqquj( zg-{y&z~&`L4Jw4VxnugePu}?2sY~<5>}8TC9{$oB-+F!Jt;Ga-)li_MK&ZO@Dh}0K zqC+SO8W4a21c6W>H3SjVXKvea#}jvb>&Jh4wT^iqa@WrLPX6Rb`}ArG{k*geHwp!y z>iW+I1r6eZ!a4@=q6AscKpmP}KDGUc-+bU-{oDU=RnB-J@_WDY>wo{p&o4f=(1mse zX;B?u-`a8i4R4-%^{SooBQDp7@M7c!dDGc{IMsu8 zI_CFz+{lN_$LAaS+o0tm8YmLP!uQpnK6A_b1HW+JU;h1vs}l0$=fC!ozj$eN|GD0n z-)9HD>gh@--WvxPGkB;Nyifz*H?{TCyN+ZZx-p7-c7O8dv+t~*T}h#Dz!AsrS$QV|(M5I48Z-1zCeFCTy5ik+~(G?ISw1c z0sx>gF%lcC<|YwPXr)KgAX96L37L9+rRqH9{a;T{C8L4sP8Jj_q)IGH~-@Mi?1*Appy+K(A!Zo z0F{JzM1;fN4rL=06E~7@B8ym;DqDD4WHweCH=0im{s8XYV@x%|mTi%OK4L zSzr+rjY5GT6g&>V#>T;h2x$~A4ueHGvW~|5T|2(|&pz`n|JBv6o&5gq{>ERATSo!K zFjg*}hB_YwRx2e#*%XQr2P7Z`LV}7QY(Q)0XKy&red~&x^c zht(94f&xpw555xFG2pv6yKxy#2f&2yn^1IF8hi+09j10Za{Zz7YNkYc^v$P#e5?cQ z6jC$r`$N|c6)47ze|{*&aM%FF5ChC@LZ~pZEyKHBD4|!6`!2Z7+TJ3I-oexkiK+Bs-HGXWu;Cg>DX6 zJ}`1$P+%pvyFh<8YKB(@D_?vU4hTTU5YKFzfA}{a{HyOibGZ(D9{K8HUw;1IKfio- zu@Ai*jHyHeJaTy#>hBnM;|5iPG0U%VKv@<;2||MmAgDuQ+dbDE7soEsdEZ6u-geL7 zZ|q+i1V*Ef-;G5B@2wJL_|LqFN)#hSP(h<`d}AD-K}8Tw!StS|ZhiG?443Y)NT;F#4&XdupD|7sh zv|J;?_mGG7JoMI|y}k-7$*2~}Zc?)+T^<0i1SsB$sCu%>pO4&w2k?xQm$b2*s4P_+ zN^39ZP(~0oVQTkdd-nIP+$y$x@xJ3fINXNybWrW_uJrq5w2PatAOVQ+qUV_Kn44q< zd%oaz==h+3LV?hrVu)wrE%*G!z2ABHyH^AT0Dv8x?Pm|1>OwDvJRh_JCu#!&G{&G1 z<&X11pzsWC42mim)zq+1i2!sR>hrhkJYBzX%ZVPp=d-W=$;&JKr9SjCFqPWC1Qf-w zM$<4XD?ijpC@OXI(mKGOuW(Wg3$REHBM6$%+WqLB{rxLv9k;}{9Q(nc4z!a|nS_gg zV55tuSO*qA%L}s(01HEc+zbj773)x-Vu)HWbNkote(vCpuMiL)O}R#d?99}B(BT_t{<5LyKck>r-eSPJ! zUoH63gHJsFFP>k4r9LG20E+VlMgRyja{4^s>^7#uTu}*NEPJis2655^8XLoc8bmX& z<$?eDfp7l9W$zl^Ieq7$zkhoj)>FvxN@ujH6+;^tg@!{YHZ}uCI8^>KW*q=#R68jf zs6!4ISce1=7S?g|j#E=-E;kMUu(PxM%z;x~=w^`TW7fe#|1ida3XAXi0#u^>&j7@s zbpYBCBUZVvR0%AD=AZ#n*FU`HKz`r~K=BckYcJHFS9W%`pLq3X!GbwBQ~Em($dwNO zWI|8~3Rw^cWFjC0s@x1NZcA_a+oHTd#jgkiC=m!ZPSg!Kro5Zz9oTfaKbOw^{BM2X zrw1;VmjCjXzjo%Cb7vP8dV_*b5%m{13`2nu3W=bQ6@nlhf(EvP*4R534?#=Vcb5jG>wsUBrE+bz1gq*#uINIx?EkuuRrzFnP<+O zId!@V-4ybCEGM3*kqoQ@6mjv>q~TtT_rzfnC_n-bA|r5NeVahRzz)0v(>vMT(cIbA z*IuaDT&@w}Ci2_A{PU-tSv-5L|veB8fmnR5bJtG{B+aE~+0`u2|rzfj}it5D3LX^jyMT36=Z+5bwaH z%l&yf|BJu##n;~2f61ZvsLM4XoRr`G<)8n?|MtDbm9yQl?J;CQKQeM+fvgcEvLGCJ zx{AN6&>;@@LW~hW#k_~64kaZ}=>bI%{~~PcISq0V?;u}&Y4x!uKYjSjr5qc1{LV*S z{-c*xV7YMpW-`NYeYCEzx~TU|Be6kdyDO}-9d=wE6NR{P*)F1UgOS=#yx)VISjvoh=}Dy!K%_% zbsdJu0gRL$5eRtnQpFezl!YL(^3v*OpZfHng-gSQpTFyo7yszR62SrdqfkiUrcX)_;JI=}bUiox*_#lUHUAk0I z>^QUK?5Tw=^wPl{iD3dXKx1efgKBX3fjEA;3K~NYZ~)Z#p%~I(1&RR&F!EUI5QbSw<4@R75Zh6}%V?_)3g;S1x|0h<)b11e(Wk$)H|MpYlE0tHp#qzNdX0!4)p z0me$EZj&szj10U@^Mx0df9dzHap9O;Bf>E`{r{d_?42uE(2iJe=<>L09vB(Z()$tAfsIs!sTQI9Htv>OKj~+aE0Py34*l?8d%%Kz^DHY*-f zBZDCal#Z_iqB@tw9&B>Fd)vNS&*hhZ3wNEHUpRTXQ>m0xSP%dZ1ad%QI8^;U4Pt@{ z_gChA%1_3%;@zOAL{ik9_b*@yUli_uT*W{0gk}AT1n)-7q~c zD3b_eQCXNejDCnlAWT9rKx2b}Oh7TJA>n9GEdU}2z|v8aiws9v;lbHFKl9v5Z%gt4 zarijNH6k3zuEqItOJ}-+Yhl%jXzB8bYL6IrI>w5>o2c!SzpeCq#ydd6#0WNWz*rto za=^$-fZJpml>rdggKNLg`TGCxb1%R8#zo`skDq?>hkx)7%dpai)KsGWF*^^4<-pVN z7y{$9z7h?@%J|TDVl;#WH-Tc34sp!!m4ibiQbSM}*tYXMTW?yX4>UXT$c>+T`)}SZ zE25(*p;2HY5CW{^#6zb)5%`ZjDHA~&*N%!xTp$!fS2$=9L4^xPH8BRCA4?v1C8N}5ln8Ey#(AI^VN!-!MQRAJ zS>dFB!h>tS)c(ca|NLtQFMbKxKm9L$^}GMe50_!N2dNp%&_T6G&VU@06gbustv~@) z5XKV0VO+S;SBz|@k|Iy$%EMm?ODHyufEiff}WwFVmZ0@eCYIU+J??Ufp7l@5oxKC<@7%SR0C!7RP8 z`ax8D`P-|Dy~Q4+*%%9!Moy*cry|CmWI-JH`Y|-dn zAw>+30B_D@ciwvYnQZamaCrJtkH7RsudKpaAF_(;uRx)ylOW?bz{C$7v2ylJp@55n zqEMn@n8+iJc|9x(VlH{J_k~}4WdF&F9H+XcdE1fa4!5D34rXP?E=UyRP?k7}!vq(? z1RvnI+H3*^oEM7nd^oa=0VxUup18V%~^p_}`=7LFF>FIRg10S@5z%^ zX#lWXg}4ES2`F$AD60OhYRKcG69P9R0V4v)j;0Sidf&0t_ni#=_V51s_y6Y~Ex~ec za7m8GRbntIRp7u>b^2q61sFC6i?4|DL4oIiVlz4%hobnKG%APD57pFm*y2TyF00-7lfeElImNEn93)$Uw+p`KI_7>f)lHL)T^9wkGg6abjPwU2Zzf&j9=@2$XUe=sh)fd#{XX)tb*=Z%F& zNJtX~auHArYlUO#fmreNSl+ks6Rp$YS8o^X{rBB^mKX|bKa zK>+A78rUQ(7Q+U?dCX*!z@W2P_kwwHK&B{k(1co#>H1KKN19C)BOlB`l%>M4iYQc6y!_v2 zx}^LTN8>XU+QagO_1I$0VZ)vCH?v>)AKyo_@Ylci#h3og>#MMqfHC0Aq@5${VInvP z+hNqqFIf<(q$mc+kQi_KQxysrhoUrJ7(#&~D5^<7bwmKMEEiX&Yj7|t;P=kmxb%MV z<41Sjd+3Kp+Rz>L!>X|nly^nS8(^c5f0zYAartrd+p5t=aB{b7#7cW?)MetX!H5$^da=Sr{sQAH)VICj35~ z2Z~XrphAb$)Mp4nwUko+LmsU)DpjZW7d}6jKlNLWzH#L61>*2e|H-dD_XjVmjsk*W zlWKW$ln{clT|$+)f#IrPM4Zfz#o)5=1}G{Gg&`Ef0uqcvQH`NT<)mR8I8d1K?&(C0 zj6P0{001BWNkl_L`}DuKw=fS{-WZj1(Ck^(FAKW^tR)~9}>Xm zql^hEU9qZG5DXpNSdfGjov8Y|@tB}8h=jhH0~MGs0Gqe+U;5`?dF71@TEh96ou4@L zgClL|mAe$iuZjnwBKf3^;HV%BD2Bnocu8;=5R5n1fvPMxQ5Zz5xbaaHaMUCl!T>-> z02{1hNC3$~z8qcXrj_20*3T@Ttpo%k7A&EF5e~4i13I*kftMH}03!ntmHNS`bX3U# zhc2U9HK_!^6J?}PFbPFBy+VY;#v^dw-F5T61#?+;FML$wXPO9q?eWjQ@~3aEK_>x| z4{idDjefD5==}^$U5wWQMd{i~ou+EcizNY!5#gxQHKMg@pj#=1ZAcBPk#adOQq2g8 zKVZM?KKuB6hnC;FK>FCuPaJygXdC(|SOaXwu1KFJAlRfHC=sCWrisx1)SO*jEQ_K;JExJI zi{bX8p`D9i!UrHWbUVaIvyrG0;*|+grJqr4?@xHVipfLOh$~f%3V9%4q2e&i(aHxa zz@Boe)9+pP;P0B1fy?s~c3xbP4I+6Y&keH0cDAquJtiIe~i>%hZGU?s<^ z65KG3uVhEn@rV+U($V=LY}G*p_{83Qr`{{<{keM|-v76U*T=^rhc^Tu7+#tj`rq=$ zikrIos(J__F%AVzLQ!$oIR1kkow1S#4!lvTp$kbi-Wr5KKv3+LCq_afhDj(&cV8SMTLx6Q?Kcq+R9(lgb~3V& z_ksdp{6Ccduu?OC3MN%3O8)_VR4pHx1_Ibszj(pbqmQ5b>=NPEZhzq5w~w}=R}6sJ zN>P-l4E!gSW0ghDYFJm4zY0=>!s!zs5|N}0Ljk3lR=ob0*Q@k<#+u&akuGj@kcEm@ zxv+G9DL;769mjg_HW>C`yzk`kh0eg`c?UQgkQt1{i*Xz(uYp$WxhRCfSU@mfK_WT& z3JjsBl3A78HxfYky^g9tBS0#JWdJN{#nlX;_&G5j^H2Z&=U#u;J7oNtJ=b38L6(m$ zjAOMDxM36ms~y2XS_%TjVxuuMki_VVQ1N=h-dL3ZM$!8y0URU0iSlQKIgqLogF_Ag z0~ZotrSZ}EwKQhxF=4Ch+Hm?*d!+|dk3Si00uE4qNEBG zFbPGK2C@3HuG+>ZNE#8qWUx3uwPGEWuz>HmdGE=04UZn1zvJlZCp*wj!Bx}2!PQBL zJjQ|}3as?}MuXF^Q6Es?z(9sjh%y(XN(HD=Bsq_}Kqxjo4N0-$Z^|+=dK|31sc3}& zfMtICiF*$&UAZ^BK2-9vON8)}UF@y&2074X7R6;m(6{(&DHb`}wB#qI%cFu?-w4zHd+?EUTk@;6`oKVM#f^KalhJm)^4^FVR0zfc0;~?glo5b{kvkif4GQlsk%S;g zq-cx_fq6UytaN}jPYtVq|6~SG#svRAdvE$IOLp9c{W9~Ms_whIWoAGC0}vEffZ$>- zCW9nMabHA=Hpmb}O0+1`U;Rh;AMqE5?T|kxNQWb2*`#TQ$>6?-gB=541~ZuT?RV+! zsyZh#{o&Mds^1%Hu?2{Ds=0BeUw7Z`s;pdpxfP1of*#VC*(Sd9AN#xC^@RuThzf?! z<9^zBhi?mpTZj>SBz2e_zBY`t&rg(1MoO9P`8rO zT2_dtBnxX&(6|TiRebcn`IQ&``jhWO3i^Zm02h1YDIBC_zEa7O(o{6NSi!l&ctSg$ zfFZ49gh!D{j zOCS3FFaGIkb4qMAE@Vu8@R9bf(>xfJom94Pu8<6qgvTI_aKjub319nim6BV!Umq*Se zLW@H%JqRnGfC5Vtjv_5{;L#_TE}<6E1;nX!{u(u|{thcrEMCO;0k(p|#?q!Y@t^(I zKl|~|K6zzT{0#11KHNPCA3i&w{&+b+RRcLiKUhUSD^f5A;!vz$2%Aaku}>uM#k|pq z4W4KVY4N3wBf=GwTmaHKGM>!T1>HS+^3;X@;#dCur~k*#JjB&uHEws>F|u+9c$}KH z#B)^`RD2^G`-{w>{0PS&EpsFi9=U6EcdLkh6(8g1(ZV`FO`<9R0S4(JXEQYdh#wuk zoF6=q6hHZ%?|Aj|Z(LQwB@`$VHn7wRu`k17W-C}&Lf%0}X4pIwH<398Zdf8y@fW!o zjYg~gmP|tJEH78KDlDMtO*2YFV_8|{#ZUl+9sR^le)o&_|1FA&zh;i7)DUi8;yVu> z>@ggrz8iRMWsZTCjyKGeAnOPKQv1A2A{3c|aExIa!buZPg@bS~A2r^}+^xiUWf3Y} zx1eHc1F-P+lK3{7R=`aFE+~NH9^ZS1Okw+Hc!0|T(s1Mu1hOU)Q`IWBGzlyj~o+hlind z2xy77X+{VtqbNsl;RuRS5N={K2G<#5iH506(j>7)1cj%2sEmUs)D*?QYMFB?KCrS;fl#2*o1J> zgp&dzdD%t001qn}S>65W@)x{df=s6KL-hgyn51KY_{UwoJ-^jHjXMjUMnm{(KmOw{ z{)?9`u>sh-l691ZoZ1!;uU(L);s+&zxj5VBjZPNWT^FJfxuD_xHQHsP{A>W zFo>AAw5 z3zxpSWzha{FE*i;nHkBSKUcmn(%i zU*VnSoJ!>(39&H8O>^`8@B90I_=msz?sxrQ46SgaDyM!VBQxGG zyI+eKE_r}ix6iHsPjnzKd8k(?Bf}G{!|>K$JYhS>>wod~0o^oEbXhnIAqXj-Pgi=B zD4h$z=2NA`SEeJ8FWJEu!^y3iANu1z{@6Et<3HWBHw!72Iy)@kW-TMNikM|&=8&l% zw8DqyAErqS$YgG36?$F*&>n=wu7E-K-~u(2?Um4a<=7drgqBMu3@#g;|1Z z%<}L2Hr{ya&#rc_rMxesaGw^p&6it+F|=Io{G?YeECgIRyOkXPh-?PIcqYZEG_S`M z{_~zY_S)y}T%+rtY27ea_6m*gz*NOBFW7og05pTfy!MlXScGE;&D(eGf8w*Bzqop7 z$k$m1ce8QZq)&I%vF3(423&(<6Dg=B;!&n>gu?2yaRj%J6G>mZTG@bS?lgDqKH6cJ zBIAh;5h#-cc(o^w9*YHQ9A)ASnc!`~YzQef;Y985&;F-J_aA(`>mMfV?MX6%`udlm zqUw5AGE(dPI%b??Bvb9-22cbwSMsy}=!ZY`%E|_ueUcwyf0)LKF4HzzBEE9jJSi+* zN(xr)Y~4?}OxTzVA%zfHz<%eqcWrm8YO^ zA%#pqVe^LE`?nuS__zId>I~t}f9nU|_~gB-waQz@C`;WiH^(9iFnEl8RX*ut1;^%b z^V|=YyZxJo{((+b(8sOvB^Tl~_K72vSHoRY^ZwE9x%u5ofJkYvHgIM22P+T@4RX2X=-b4cX9I{lk+-6UeX~BGwm;~U)k^9PI|~XxLH{f zI-ksv1_NsCg@rhaT3fXctn^})8=DNk+}IUnt#_A?e1coA$h}7wy9o@`B^*=_vR)mq zvH^>G^mwxHNZ)aZW?+_v;o*M&M#{Uay_q@;?q1zbz}Nlsm1SG$_6aLqOk|xYtYC9m zwBF1W4QP|(jqNIVeEM;EG}g_IzR`#W&MQYIMwmp?)}OX%qDSqr_z-4#w;BzmgeiYjGb%{(}` zo&Z@}!MTo^CM=?=Kqj7ZHSVUClMX}L^}}V#hiqwd?n(+|sp_bk9j4s&lJucDx}xf= zmYC=92L&K)M~&fA=dZ#Cq(`4wtz3EZxyu2`9^WI=oX<;!=WnDn1?m%C{d1kMa(8o8 z&3)eY!$qI3bM8y>WAbuofml(g?l}^s>J3%x?xb_)YM4pDYhaMakDY-*g=biY{^#EN z!I=*KJwdNu-v84I9sPypKh&Yi(1|O6 z87*gM@#r)Ej+@K= z_8w22A-wpD%N|MLiZp3G7VIGe%9T;!`oWRvU$f>cv+N*;yBDRG)l$|$Et%;glH;4(O zm3cds_W86c34bgaK&g210`HiQq!?XYFZJP1a`5ZGVWkik|N5A8O9jE4r^$$1q!Wcdh zq;?4A#2*no&K~tMTyf@7zEqtC&BPh+;Nt$zq_Bjvdu=HkJ$!thp;HW`068+i%=;w< znz(Lu*JkhJ*gZPFO%p>-QE-uwk|Hgtf7&5fDee^%QCELdf!;A=tnzkC#o6o@gqjpI z8Gv;0S1*_E|LFJqV255O+-MP4rfPJ{QngeY;3FAXxdB7=%J@I5{y+Dqf$tXpfXSHb;jcCT|gD3IW+`bxTc27T7)9ID;?$5h_qk!YoVSI^8v zWs`A?Rc>wK?*ZxZizDdq!YBVcBM&$jkg<0R8M_{zo_Z+b6kSw9!>izIR=!lhL6y%t zACuynOu$Tw)jO(~8*^N>5a-zHOoBacG+fFBm$RKixbfU(Qj9*qum9rDmJ{eczgMV2 z9q94p4sUk&!T}#IjuH5LGAFBhw8o>BQ0&OG&&sZx!U&K1%ouZle3jv=z4+Q2Sc9>P z&#_pA**984+0$;I(RKo3unt$~;q#+U@Q;4!=O*p%06Ki>0-xycg@n(VoDmVhR+Urp zU8v3W(kbz{zc}k$%opzNlQ(eGIzda`Z@FZwJ&)sHXoeyt7MY{8#cv=Y3NyO`BPwVa z`Re7d!SwozcN3D0&MPI{-QjZ`UNm_VW$_3Om2Im-w3VS+YCex;gey{vi*l#Kd?rPm z;-fk%KKmStKYA1|)(lWh?V02Fi9(}$RM%HqLVEZ&ul~E~*uSO6(`5+1XZr&QS2yr= zj#meGMh3ja2O!IgKC1NHjHu9YO5n(Cr%_<*rQlV@W1Rt7B?+t8VwLY%gJ4{#+G+#v zQeO$vt_Y(RSOH?IKr&ENW1e>oTo zpdDT=y`BSlMl;1ZOXJFvg zhIX@6C01(`}jFF9e`g9pW-G_`W!VT7;GZ=#%{a|-NAfB6=msC()u?alx_|wWrQ~^%q|JLv(YSdzi z@Qx|~EA6((*itXE?qR6lj@n3!FZrZ^9Wa9`5`d5W*hj8$eTuw6x#z9Ew1+%3}x0v9P(?s!zc3arTJ!6-s-FZfn(vFtTk8Fej`fZ21^&izc)4fAL8*88Ny%t)xUQex6aXA zqf<~s1l%y(;%C)|lwQ^J#-fF%2Qv_Hgj3aTThO`L?^}{6m_(fG53g0jNB5AW|>bhzH3ACP+_0V|Y&Gr5)Rq1#T=9U5nY zE!w|!eyKjCMJF!R4KpDYD@BVfTt_+dc(_y1Y93#3d~1&1x&E}uk(h0f6;e1%Vfo$w z;O%=azmC@~aB0X1IUp#ELFeJw>;ouhy8i@fSK9wb*{!tpnlY$mjF}WGcB(g$FRH(q zu2TIh|D3+`NcGnb)})|0mkrO*?!g|w<;CtE-e&Yb-s1q6A~|duPLmBprs>Z7VM{8# zBF@SoTVj+sCB_wOcf=Sp$q26;!3u<*<72KFV@(8FnTlBwk9ZXoDIAk@j6T7gi(mcG zA7StT*Eb*myAH`=4iCbhA*=7yO$$@)%=vC2Lk z%f*qTti7U@gIJMbCP*R0Z+`S=zKZJlD}02n_6dCDj<-JX;#+v-U3lgi4-M|H_u%Fp z?BXZ!mg11}W!$`fNN)i`95~z}-W(4uI%4s$NRJ-(c1zJbeCk<3aXX67Wds21ZbSeW zZXkw($h|bpj|n7$^V9{$rM6(fGQ8yNeQG{-0uicR!lS;!B)D*3cT@Q<0pW5ys_x)+W} zL8XpzzB<@AeH!GB(P>|DNQDy&V29Dj14cgG?5Q)KVC5rd#9V7q_!I__!MXk|=|$>3-<*8A=0_waL|YIlV1FG2RoDQ z5ldfc{AfWw#R+j9^MpXdN5and6>w*d*jX_gM@1T-L(nb!1*uqHzR;quZFL@bC zH~RaGi5e5Br(p{=Jm_(T4hI4hyhm4V-zh@J>=Xt+fUs%K)z!Msqm1bnl--$8ou?H13CXtzVW)zK)PbSKe`j z$eZvwb^v<#0sYLk=W?64>GX<2+r}+Oy#HLzJGiTXWz(L1h{KIKb@~{4%#QN(>XA?I zIAZ{{vq)nhYt11TC1O+&RKIQJ3YwYB$1;W~40qy%6jNutEAsBmcii0hwRb#4(5Py5 zP)5Fl?QrOk2;5);azFse+N<>dL`0+kw7dRP-u)GM&qQheVt@VdVfR_`;Rq7q2}WdE zK@j6JJU(RNvb?@}J9Bv>FR$|W8Pi+G2Q%2TB+VyNSBl2`=m%s#>0c}b@ook5=mr`i z(6M-;!*GqhLE|tXb|7nFV$;ObiilfE-Is@}KPSB^Co}9{JY4*-4sWgU5>#F7f}73g z)%@akRfPyVT`|wkRq$8!QiZ`SkBj3yTK!4auc<+fQPf9L_y`HwKmL_p&}0O(;07&# z1iMCmiY9X7fN;#(yXTa4?k*yLYQEZE{HYJGms9MoKe2!GN9ph-w`(FicKfQ!m=l}h z1um4Ru6Je(evC0DW?9HmC5lICV44Cx4%{XMZ9_}JS6ad{n`g8BURFu8z!(sQSVgD(3x5AO9yFcAxUL)))c#~&& znJ#$xgN0DjpR9zgsvIkxDW(bNPUZJV3Y$G7Ow8aTWa66j&P({W?u7o%@};d590$F z8KV-fg&I^RuCaK=b;qV&^lP{iYbB=)C4DY?XF)S%YEJxvB<61Jc?mUbD_gj47UIeqtoY8w1TN@1m58m z0C7+YI*@?!kh`|o4%&+}Ai%w7BscH(pN6YiPPrF}{r(Ff-VEWqE(u(A%#Kmo5(d?z z7?Iqm$!_#f-RCX~$Ao5KtS=t}hcT4!LJE+PS6bc+9TsXh9JG|D7Z7ZKW!UcFg?Iiu zZoG{vfCGZT9Zkjn3W4KbDagj44gs-9P)fxO@B3HLy+ZIl9f;TtFW+e2RkY7i2}2be zwfxUVG_a7P@BvLEpt;ZTh%x3;`-&RwP6Z}&jI&7QB@;6#md9A)%R&%SP=bX^<3oRq zbQ34{ag9J9&A`$nT?&fsQEobY^JjPr7?(?TNzh^4? zKotyQ+B5a9VGJBI#)2GHgWt*<7I<@fU!evqa#6DcO|wj=F`hmVh%(f3PTc_D9NQ~& zh5ZKfEn@OMBcIUi0R!BaBRr~Ju>=A@93W=<{`#-rYOX`-hA@AHBu$1m!UtQkh|MbCwKWXCG z?dN{3^j!eVOL5|Ht-Q}_ZDcqf_qt3jIZ7s=Jn8OKW<8pt{C0wkQ~9Ug<6q4airvf5 zLLSY8k8@1mW$lgu3fjYRH#9^I=@^1Iuz2ilr>ls1GUQo5h>!zP~WcCU#vx1Rkm zfC&Q3+%Z$&U&|QN&0R5uO)}yYV^}RC4yW?G7wcF=VI1HhMa;&ssnR(I17({! z3F4Ep4-&T(WAK^|i~aYC6f4FUFL^;Y7L_u($Rj~U#&CBStyISn0IR8tH((YJPk;j% znv#B{bn{pLc!~^Ru((GiP=XRjkramx07(jOX}$58@ySun zM|E#l#`DilPS3l-)t%S}xaBfO6>U+y3MklNs+w{>AUXIEt^zh0onzkv;)5B8Fz6u= zb^XJ(y-mbKaAJTC{RK0Rp$H*{O->KH>sLXv-+ke9`~K6L|B1WrcQ2ja_|8K1F?+Nm zfU1cDaH=k632kSE?ndRRi`g5WAOGp&OFq+N99HQHS8{WAc7^B8QbZKAMY1!B{V}K! z=o$kM_UIeLD_jR8Ma;I#Ft8l@hfO@qHUw#z8+RpQXHp%8w41^=B_g5l;K3iedrEh= z&8_YEcMbi6*xYV6@0}t#UgDx-#;~HV3uBZji6if4rpA+4VzPge_FrB#Wmhw22U&kW zAJMiIDI7k)yx$G5gaL>>5`heQ1I-n(K^>m6?$f1kjPX>5Ymp7JAj1eL_cqE%QP8q! z&aSUtH1n(%ci;YFkrzkY#-9BBJ+sWp+ez?~* zH$*nDo;W)6&|gmX*_jBily+Tz-+}$^3n%Tf+p`Z1=~867J^6;Iu4$^-97*y2!Wia` zHDgS6aiK%a63g#NOv>;!g(+NN%ziMaL4Y;_H0lc55C1VD{8~Kr+5v4^Py!@ zU=y}1qBittx8(q02j#Q}v00vdH#0p9S4`0@=iHkOdi@!P-@WtuC!6O&^K9SWz5U!z zxFzCv&(3-F!cbh^2N-7VZm$O=su9Hz(tP3JjjANge4o*O9g#@v|*EJJrC z5}87>0};=sJ?Mc+)U%m&`66HZwZktjKfP_AiOq9ef9IKZ{e)XyGe#jv%@`%3Jz|W> z(vOP1JkXgen0^0+F^tCHM&|AT1H%Rz6dqtDm`czHE}K|xKKl%f)ybNW6B1yLaJ8lL z!Lq@L{G>h4?(V5i*BfG|)`2waiKV!Sa1fJOKJ*tMv^LRa7~bxNw{sqXY*POg_~gc| z?*ozLJ%`ho6boZa@P1*8aW3f;(D;lWO#HA|{lyR(0TVNfA3|`rMP%{Z+hFi5#9#(V z&<3pVUU2K={1v?RJWltpj9g^zE*_lGt?ao}t(>$slO?sDS%{n|Fm1cx5la+_s%hLp z;}DLDzD(9L)*)Y}%YWtODIdD)&&BpV=K1XAcf-9bQJHFnD#nCFlm5j3J{*Fau@yAdeMbeeE7kks(y^XTUos0U23=2Y7gj+i=ci z>e&e7w%y!T9dhnt*f#NmAWZBqcLZtSmhwSuU}BL78r5;zo~3-Dc5qD(?)-1=%Cs?f zd-6>ZZWM=f>}Phj8M7LFI!t0b|8_2^jFpi4oaE5y&&%vef-w}H3cQ%|FpHC+2U-S~ zg?s{zo6rP41wBG?kbn~O8oN{67%auuW=lmTMItOE%`u!b@q|dgZOVI~^gDXeL0pKr zAWcaROdRD@?EoM8?n_WDX(9z6fcyE4Z#uhukYS}9bBBJ5X0X1E z+oV~MSQ>{D6cjb5wmC13R1;5&k`->;%{*t%!cnAA8;l%CF*a&f+8_>~Od27C3GeYU}iX(x!FLG%~iE0Ff%Eq zS13a^Xbq&UjhlqCU3%z%NIRyHtY;4HmUQo6B4cUXGM4}mEG+Ksp0Z`4j;Kw#cMBnI zi7bZJ?AkQ-yBAak2Z%(%v(h|Q9Ou#+jHo)0L^us;&m2S8 z4#Q=LTeT!CDIbc?CT1|fVaW-^B&vhzFf~lLIWxO@4t(amC%9SKU;Pan=83^^`vJ`d zX}%7?6z=;}Cowa|h?lMzV=9@MXjS?q;c9vyawm3oGv8|p2x?;-0f>#U2Mf4s{lEL? z|FT7Ug)G3kaJ$362!M!{g6hsFhy=F*90+aJhasH9vJ*^`jpM1^$w08|OziH$!Cjd- z=RsoQV6~lFBjJ>I5Q^@dX-d0Krrd!b+=5R-``#&!00PVoL`@;i#28rop*dmZF3f5= z^<27|GXa*&Iv?8)&})Wsc8d^)GNMoT5FirC=wgfQfE+>3;+ZmkDvc8awplv^M50*& z0ud8OcjVj?v3XV<+~KamO^}UgR#gWF2}3%-!OR?#rBySc!OSJzVsS@u*Zt*R7OV*F z?e?3@Gs%sLF?8%n^~V_lbDG@YrR%Wdbf%o6Gr8GdHVAQYGu41NSZ*MryNS}5Dulq1 zarmmJ>aW7_6d6K^eh2#i7RYnB`2Yt&QgCNI8Nd>`H5;6`37anM8fgGz9ZKD&SuQFh z#yC2et^iUR2p|z6PU*lBa=u^=<^U6eI0RQ`64M8ba6WwATpbo=LnNx%&~Ui1IC>*0 zvg&gxIsk48CqVN<;s%gXsO=8bBplq$9YVy!)2Agzs7CryIBiZhd>@Affgus%2-oNu zkXk-yAD~gTs(W)~V&Pz($t+tUitd9usSbb#i6m`5T&Y>$n6eWK;HCp{117VimPI0n zM1%m5CgnpDPt6{s{e6c5>_C)85K{M0;=2Ji9|&P8p0lOo6AmCN7;a^2o@e*LN>hnj zU@@~&8%2)n6p7hN(nafn0f7KG&=3&=NTCcq!}bAor-<&h&zEO%Gx8>DPhfXz;t-ylHL>=^#w(RQ4zpGeFLO#n>>ykoIOda8xrl zmJaD+deB!Pc4c%N;1FC#SAvVi^3vtdJ#^kdyvAZ%TTh6XwincQb zM`Kg7CP(>-E9tM=@e~=tzx$Do{@!Q)+4DF%LpY2`!ii!y!O5O_p|YLDd(H0B#H|5t z*@>AWpeY@Qgjv)wKp`~3r>e=_Qa%X9QbPeZ;^@;PC$pUL4n%4lS(9My#aXsquRs)K z!#G&p5r`?MCqUeiJ6KxHhY)XRz7W}}bs%#CkvT~7A%w;u?qCuoNx64;U@3ShkFjP_ zIM5iPgBg6|`DY*ebtd%BqivBom?CE+fKT{zXM2S<+&Ex1WV0BfyFoT^xMk+XJgFw; zn6+ot*ldKieSgu$t%8MvQ#Q*4W@3aBvmtN<(~$RN#7Unn2{5-3M#HsFr8_fPehcua zlEMsPHn5z#^~~FxAH;CmyvyEu!7?Yo4|3{GV?f{rA8n&gOXVB`fq}+~%4-6k+q342 z7Z=asYzys?5~6@JvVhORjpQB}F`PIwrM*aOo3o??JP{le%?5WjN&pO*Sc0@fC#F3> zYU6NDX9Gkym|L-es(nfarjYc&yv?dM&J^;lABZ_fOTN=|S*nfPjX0QPhY)WyKVk}? z$Q0FgMC zury4Z^3LFH$a-KFH+ML5a36-$6ETx$dJ_N>`&cb1rn?Yts~$v7R4;|k9C@%EoCXx= z7)`jLo(T{Na3oCy!fl9I8@+6xnLbO@2;yk`~%spb&aTvNUZF$ix=Q!)QM&L431A<71TT4oUeQtI3j zaZI{r-oVw|iOAjh;fjcZY+NrjKOhbcbwi9da=r$iz@hnyC@^mUR}AI}j_k&y?iAz% zAa`Ym+1NorE@h;VLoq@oPT+6&*7y9){kOi_YWpj6$n(#C+gJM>zCy>#Z{4Fe-)8Ut zy~aMEF^D3QdmFcj6>uX8BJeV$f`T+z2lu2o5tpG|rIk;K1#ZM5B0=If0fOLgkwz`i zl)n%OM53B#+}aB>Ct`PFX0_}vA#u-HdtuILM+_o&@0s9!h+$){W_fCTB@mgLX)@Q8 zb}?*++?T}LG(Lkkmx;U{0ETT48iaG4{JFjTvp?{WS6=w^DMAmu#t;#$U}YrRxaqA6 zvJoj=1k4oF%`_3gESY6@A3Gg?=6(|qQ6H(S-+(qb4PHf}M zD}gt#fUrTl{daEN+vI3hhX=d&VtWr=>7I7P9j+svu+ZSi+?iQD2WH`Dkg0+RW~sRR zW;U538V5EKL?TfbCz}uvnMhka^pfNX5&$wC%N(X!T*l}sWe_omdooKRA*CHL0qVA6 zDjYJvlUbhH3=|L|G0$o}V9bSqEtFW$C>T$Zx%CvxkS&^bedxJ2hW*3cE1{$3ae5Dj zfGEHK8Zdw;L)DYR%(9aQiSCJsv!-zzi4A5M1h`J)){3O$Af>55nVdkxVa@|G2Y7}v z3h-by&e0=wGdFcNA~wqoYosA!waz?i?ts+9ZO)fO>b@5Wpsczd%a6ypZFYD{*92o~ z%(7aJ9LT{&>=eOetV9b0gcEGO{U^WWfBoxEgf|~<(VRjqkqm*L4jjA#i!g~qMb0{? zn}iJ^H({%0S$lxY6o9)?=@u-K;9z2r#$h3}#Xo^Fb7R)Wcy5+UMQBMI5X98rd8`7k zG2jD{du9$yY(Bt^2q|9!>UOY+F@WAZ<=hdJ$beEc>_gf)lqtY1+aM(5piBY^U* zZ3G;Cj!lnli;ys|YO)l$B_D>|JD8ZebWNrr8#60ySng(~Ol+RbR49z*%yJods@j{Y zYBI|NrPA?a$<$2CtW-5KHJ$gCuJb0;i-3JcRh3I-T10Ko-d3;>#2Er6T1Z$(508VG>`(3Hwa+p)XAK%R035_L=3 z<#g??4ruOG2eo9Dd2X0-H_NIzHN|J9;I3-w26rvH9^I6{rf#at;xL~Wqk!LLRtQ31 z)hyDOnQ+SpOahphrPP__af+mmi8`|kXc>lLmf?wr0<*gY687Q^PyhvpK?zRaaBBnL zJp$uPyw`XLpIL=P8{4ynjok%esdP99B3* z)!p0+g+ZhvUScL-(s@ju1E$CX63D-J;nM)_#j7ov1a&}=1ya_wxOG{F>;6&7ow)`% z5jiCa`~Dg>#IRu^z|9I<4kd}JmK~ZkWz9Bi--VM}&Up`TN$8@GLNkorG=y04yGsVp z2@W%JQvzwu%&nO-1>uG{6!oIotM=|DEM_(gy_K>ZOCr%MH$fa0Iht#!QNSb}fB~5R z##4lgK6QrhaC6UKfow1oX;;_nXmDIA^SRK$b zXFT@eY95U4=JrSL*Hnj1Vbi*Tc=?p(Amk+`clxh1#@3lj;4 zAWe`HcL)WC6OYLnCdrzDv_ZC;_J(i+^1ux|sgY`O*D^|_ZO%9Gw27Nrr|)jUHb@(| zanEKc+um(xLlbxmJID=CMA^eG^b_Hl3B`mpL3t}uqobENu8>f z>RCr}r~rgPz~B5m-vr=JcLX%u)d4O|xy{$<34J&NnxMw57YmOj9~!Jv0*Cjfos4 z0KpVp01SGHKroq7Mbz@!xZEQR$Ss-{)ZjFt>8;NoCTV4R5>EnhP8TE_5Fl;J`yuT` zn&Jh8c;cQXtRC|MHZygw6%nK8?m%?QrDZF|4UxsLAuy2$i@Aw}F)(x|5VH``ra6t$ z0wx>@uGRrO&MY7niA~%zVe{PidpFIwa13Fa(!n$jX%~f)4rTa;fC*3x1T>HcVj#Tl zcz5O3_VIKX!tJfoYoq}=flmQOWDr3v^OcyHYePZPfmqCk5KnR*hT)nyGKXcLBQY1h zlB8775C!5m@3HNNUGd0>#GT-2NPU@&HumXTsYJDT;G$Yexyw4lu+4Vphijr(nvR*- z9f2DrFmDWjxdAAI5V$!#eLhG_h;SzoA!=9%W~LdPK{L994lso?hMVsiMg8V`PZL~` zHwXjzfCeyusC%cqQwYSW9pFtoZ<;eeG=rsl>Z<{5BPodCwPX>OXEyAElu+MDTNxNr#E2*OgRXZ>(lqKQE}CzinO z`Rw%TMFJp9k$}j}MjAkoZNR~h4LKnxRDg*14d3&A0KfCU|3Bot+t01pb>{Vq!<_Sd z-?hHe-n;B_x$KH_>?9%%4M|8^bgOA13oiO7kbu5GYJtQB5<=pS;1A)FJ0w~NBxr~@ zsheQpbnJF)$EP~&(|1^Fz3-fJjKRfRU&ZY>j)eqide5tpO4?N#`(5)e#`FB1|7n9O zvLF<=!>ULIGqgpX-q!~+7gjy%IINUwH|u>H|4T$X&U@8)OlpZ(Sh}^bJFD(gl1Nc0 zTYcze!(?Vb0c+hv%4nty94-+9LExmjfVo@kTdfD-=yn>a6YDi#bWSfB?`;GrNJ*5L zOTL=QP01HYW&-choQVf8B|UC-?sBKc zMzNoJ%F%P$jbpD{WlFstw)SA&m{J6pHM7p74hLxM>uM|DESyrA%QX`#7a`uIB@rQ_ zW9wK28nA+Nzy{RvGt>Bs_^o$8e~(iJO;7>?e2W(|I6=CtiF0@BR;!zNZ|(jEjE-S_ zW0J>zNFsT(I^3IZ@(AYS-kCJ%#4I`OPV37EMnG81dI07@B%=ZIN#|q8kVPkVi-_8{ zt=?x{%-3!mNCUy+-rd7&1u1bp_G5rpRET%;GXTmHQ{Ja3@%S0_ibF?rto(=|Uf$XN zxoy*b9_!6I2={N5z_g)eaEE8`u$}!2|KWche?Z&00nhOO#0_%C@dj56KD6gT zY|&5cu=Ta~jX<^D3Asvf?;-^OW_342q_m3&<_yx5mTrwngmr7DaZ8w|DF&yZ7EEAT99^u_u^-VcvP7JobGCXOD z7@|}rjQ24KY0@R@UZgN9Q3_BgSD?g_0f^4abW?ks%aeGVgV9+FT*D0!L^S5dNv2v4 z?wwhtd^xn+1ceXpjStLC@0+_>I7qV0!day-DZtBoU3>e4w&q?dHU^(?NT3Z{flScl z)92kkKC26sjC8~)5FOi7TnePvG|N@B&8%9OAZDG2kXQpgr7~v!qi4&US(31-&IC?r z50FX$QBFINygs4|=jo=~hUgIvPChO+B!~z%I^QrN+(q&T7aPr_l6JM9A`}S1urMWJ zC4i}%hpb?D<8wHf?&h1?H@6MYaEO6G^7u5YXain<`R>i1#}57Hw%#DI41g6^{{9F5 z0^a&A4hlaZ7Nn8Htg2fyVw%(9(UYjbhv<6fG9Gb%lw=Yq?sZ5;lTIQzU@FtO?GrZc zam30z6k;(D^{TU3A1}-Eupo>%P5CnGY`#TwM?G6Le5C4$oPXr-FqOnSjQL11G3QVA z3y((Nt*`84R)@rVLVAX$8NNrk!1CpE7^V2@zxfxx_vLT=G@g7P_ut3e6YL#sP>JMh zBGPPA76N4!3lH)s&E5MjLY>num_*8ut(rB!MGFWKU8FGQ!5?5w0Bc%Q$`D)#=ahEt zZEze%E38`u5wk4QQ-lq}J`uaMh<+ALj1x4vhh?3K$YDteg0tqcj)`KZ1h>AyO+6Dl z&@<8nCLg8v>9_9Yvn}D04)ogJ#_kUNfO?JD-~n>tq*G8tSRjNm6RTt=$)ZGTR+$(? z?wyF3B&B795_GG=%2LK9soNUiBfT%+B9rPg=qJpgnwWL8nh64m(eX=ZKbIS34e#CS z`PuD_NZjftx|{AzHG>Gzb6Tp^A~V92MJ1bUi4zA~Hx2~)gu<|dl);yn-ujjIKB~u2 zihlZdUS)?o(ywOZv!R_CWGvZya{_C|aFG&&{1JX)9^B!vl;V-Lq-xHBTbMAa(h!Y~Fa?PA-y;Ui#pFEs+T--p!Hs*`N z16 z=QI{>It3uXx6w`{s zXow~76U+=+u>8IpKG`U|zTZy$0{KJS6L>}*c{QDSjjA%4S5Qz;_vYauncSE;Ye|xW zbo9f`>pXobVskguJTjx1$5Y;!Sakw{;HsHPYrR#S1Jv3BOJWjXu|HO#3V;B2Tdl85 z6cJ{1%)^;D9`9t2V35p2%~k{}CxDU^3hUk}qV?`(g9pKg2`PaE^5ogGyX!YgEc3=4 zg!T0ClSBRv9vHkwt_T7haH`RY&dpCmpQL(5L}Z;9BrGB-T8P+e3->V;%xO=QJz99< z$N22h2>}P*?&kqQW9NBiazeXT2aI)pzL~AurK1+486|@@#LwWZ7540lUwF~}_@Z~ee*bz+ALDp|G9j(# zfmpG1bY^W)M;{Lmvo+9_Gm|9E;Wg0=yjFdtA4*cj;nr{H1u&K`!a zG2J27B1t4GXJIKigB5`J)@>W&y+<(-om*NlP^jZC&H*;t03Xt!h|VCDETa6#ZXL6+ zq{;{)W>Avs5lJMcCF@Qlb*n_2(~jWGIi-1UZI~$O)s+D$s(o zyW0O=fB58+_;>%qfB(Pz`~S@j=|dc^P!4Dr5}*|x>^<6)E)C}1Mh;)NsW6iSC`n41 z0azHqYrPlA2p^AK^JZR!WiZ_k?L1s3A&Mc%PC6x>5w5Hv5)sT|-slm_hoCGyuk#yVGlsVHXNH7q|2!4fR%&tRv$8zwH_R9sD@6!r?3>{g7oxPzVO1=|F5>>eSjw!4jrQwdjtRJscpB>;O}ATSbz2&yqpGvM}o)`DxP z2oc7Nr}aaGb!#dLgh=VOwSG#v1e{3Cdbf2~uBKG7PAbYoS;pO2Q<{aO)_e0!C4odA zHFd3TM7^5thm%a!AKJhtiUfi=XUQY7m08RxqId5DFg9YLx^3p2h`KdI z9sbL$-ib^gjB50D*v~gAI_F(Uv$7KTI0cgyKa)tetaJBGB_~NkQ$TPF3%9KElrAjH z+}t~Z+}qZU;{>|Gl_DnajCn$uKE3>p-}=@MmO|{g+{=b`K%bHJm=w(5Euy1d<%>?| z)*llQ%c+K$6SQS$7*<#c%t{Bu(&G)RaZM3Q)dg}16m4Qqm2Vz&dXuq?>$ z{?^Za@BaRiQrzk8`2P0@aX>df7ZTMk`fT-<(IfIxG%*B11^IlnVnwGpb+p^}tVjUfO zLPXSNE0e0~_zXp+I6F#WwRCe9lm8HrN_)t2WRiq$6B)$Aw&>yJEvE~3RmnWeB6;xQdq1g`L9};YlP*be)~VzR3Ij`G7M3j8 zq6=}gD$HZ3?1-?U>Iqh4!FKO4TBY6D#5fu{X?#4s}?!AWhu)g_m!->HeGDCLQ zEfB)=Pxe0?zsKuKtnD4_W~2{soRBL#qbNj$TWla6I#om@$*mtAm8%l&%9&V&$;^hs zI6X%ACgGyR2E^6d+0IDnega9+qO4QC6rzZxT=*Po86v6MDx6hP>!)$oS?is7&ziC> z1O^;LAWkgqotYzu2_;QF+$LahPn}mkHdKf0FfEWL*k{O-Pd)ixpT8+UnNQXmcMt-2 zefaLv!}JQwsx;lm=i~5xUiZx)rmx#KZALNrh8D$)jK*#04&9-~v+teFppG*M9Ni_3%TbxGwkobw9w4XcLM< z6C@$2bK`0_%NbM(!2u-QyIXiC5+QA8+h020(uv0`he*1uOWB)u4-4V zvy4vH0M-bn05mU*AQFO&M|t?bxERiab}(2XsFOzS*aX-k8N2}($n#s5Uq0RcP$_D< zx_STb3WtKsfPshgc0*H=HP+Qm79B(pHfCKVUzqijcCDWxdP*0qZCO-A;MF7CEzUY7 z2ve3ERJzx0Tb5K(2{(^w;obZF@#87Y178kA2aC+Lt%D6ZUQy!*D3Xb|_ftwsgawG; z=QPl>0izLQm>D80LwnsE24IKs3>OSD&;{oGFWlVbALdPd>F3`2<{y6F0fHvTJ!*mi z&cP5m`Br@$`XB(p*}c!xP3xyY;%@CAoLk?DD#GEl4RfuxAr$biNpcU5F!!D$&pH$E zXuxf^$B&qkY8jrTV2+^f#xNooeRbh9<$XzefVv%%77wevMTA=wPLEo)W0ILk7;4tT z`qtKpQ^23%G68!iz|U~K`xn3PyuVpWnK$$xoUT4Y@4t8piNGU;fWaN6(1*D1umQ!E zNBdw-OTbdPsr5C8g*34+oHzl#wk>Nx^ln?p%b1YQsfc8=!>K;76edb6Ldba!0+F7{ zWGqY&PUZ#@(c-@K0En7xwH?iEBtHPkGKa58XR``)mWi0dZS1EAP*Cb3p&Jev`5IZl zga#B$yKi5_pDe}C{p|kv*IvGZWrn_w;{p|k!5MtOYUtHg5G$vVV3$Neq&kIf05OpY zBRq+&?GT{wE<_PMX(3{jc}_c(?6z+0Xn~Q8BLF~ICt@8rx}YFRMRRu(DaU$GOddT* ziMY0tc{kgXi-U<3aArj~I8?H`GfBXi*sO`8)iom1Nt1BSX(ohu3-Sn`(=sfTTRX-$cfCbewc6drSdmCQh6p(& zO{1?)q=;b32;*QfuKg5f6H0;rbd9uwPuPFzFMaXj)5D)E#i75y9A%Gez$+XRgn-vL zu#;$UbfRIXm0^q%<^fAny&#Z~CrL>X!c~$=uGW%h074=p07UYfig4bxm&{@iAd-j> zO5PKRO6j(Z2PoWBXGCAyA)iLeq8u}(U7>oQ!45rrmLR9lBu z2tc6C&?le;yD$Dbf9>nvegB8*@Xcc{FJEldGqS;7;5cI%pROZ}BSv;S#_KD27?G$J zB2_8O!sJ;CAykw|n22}^Sb&&CNrEU#naj0sTDRB2T&)WcF*BT5=5hg|IO7$`!*afW zw`O&4$s-00pL&=B=FU=jKe}7Vdq3aC#yRcb=HUe;b%A3f5HxHHk^XCmd|2m;gSQw@M`S_IzuTKhVHmRaX+D-&(K zmb4oe(KB$1C`;*(S`W3?wH|6e5ka^_SiskM3rb-X6hY&@%NEW&38x{r&@?B#U}8jL zxJV+FZY`yS0P9US5sV=0!A9Do;v~=+=@}M+CE#sb?7#S#S3jx_&+qkq{oZli7R(1U zfCc1m10krh0bm}KE>)Q#3}6IGxp6xZ(bi6?d94qs#e=ezwI7nqqo4U06=WjCNxHQF zPTNE4C-+v;{w#m@cB;qlEr9M8;mjHU%RI2z1Im+hr&_`*6PX(k%vw%6^TyzaU=W9J zKsqNcKvxjKKZ_fNT_Ing{NmsJ*T4SlAKvl+oakzKeRtajdnh@G5gExrCGrEE0vL~V zVoo}nH>Lnobq=o}Ip(yZZ86T~Fu+dMr}nMYSG>oNci9$h4NZ{g@n>{^HFCU-|d}>x}XYSFdnvXgkaTVd7J4!ZPVZTmqQN)j36- zOVXLq16=!2MIF+-9@pE8R=FP&Ud^yx@9xP0w}_lJ!$gsE z1i%_IN7yhjhgE@)BQ{siCH8;|Vu5t@w=i#*-~ZD&5l^lW@1HJF3gkHsBd7ZTYlaM0 zv#=1{!k2Pk-h>In5pKRE$w~8Ck4dK~U&1T6Ogg&3&J?XzjUniU78z;5 zM2II?CLn{JVDfiwe)r{%yb=I_(JS1x0x{TYtOeN-FL0~SEUCj1YmsDtN*ewUAtufU zL)e`6TVG`iW{89$>9`OOJ{hWUA#i}0A(E!No6F^#_qEqkyAw$Uo5~f)BOsELS;>>A z**d&*%$j5h_-KVGr;%9MZ7XTPAi0DKgah8Yx-wz_NS|W4Kwhyv!^P7tzVlK1h$aDm z@4u2_xAm~;nJ+^F?D>Fg@>x|*u|^;f2><{f07*naRAimPHl`Sut8g1hjZ?W~(jm+q z1dKE9_!Ih2Fgwv2Kujo%060)DkQKhi&0qP?{_QV+g%OcT32+wacB*}y%f(tBh@d*T*XC{L8wnI} z52FFwKmQ3HUR6XSKdPCThGxe5xa>2lSsk*A*4NPhR9&*B=GOa~(**^D(&)`7PZ?9R zF3t+-SdTdFk$x6W4mjQ*Enj@+mjBdSUZsnr-X2azfqoWGD(E#1S6CWi7rP^!0-mKz zX=z?_nuJq?5xTJOV9T)dembl#bD9NbYZntvZ9_ESq@oeg`bNwH0BzCWeYJy<u#3a^O4>K3tRwlhr=Ed0Cpwi78S(GOr(sM%C&n%bb#dC z`;y*IM6^uT?!L9d$X;j>&DJC%-C|&}eY}sFH3~blTSVkEC7sSpGA;0~Oe1_;CDnc+ zp4`3GJ0kA=IOb&XsJ#NQd5xgNskI|K&_ck5y2pHrySK3b{R&wz|KVqT97F4!&tUuZ z=><*;W`QhNPFNS@hNh-njG2W~z=V_8mUJ4Kz!Wh+m%_5uJ7SsgPIWS`Nm4}Aeu(g* zOLrTc6OVxo9}e1R{nYz$p00?_nV!r#SnkY1BkRH&OR4P?zA@*4t|m?dpCp4gU_=~Y z7^5;5v`A0^FGwr4pT#prze1khzW!QlKc*BcF) zpRdS+7!ZsIQjc*n=&c{jyXqo9Vs?<(Nhp~&4h=hrYnTa;p^P};;g|8Yp)E-B7oPpj z8zvV0WWAvWA%M7ic6|T4Pml=o0tY)2sHvm(=qdyD(WiW4eo)yF4dr)u*f1y&tFQ_Q zGc)VM>3Py3bmmVEs+M_EmL$o&1%d}bgBU=w*83(hDGPHhX`&HTdiEP_EOXHkUIQLp zmE~0Lm6b4nxe*>h5@umRjTk<-SsUul>7=a0N_<8pdYCe+Wb=jq zu?S_6+zhhqDIlI-0o$^tgCNR+6kBLbub@@7;qa5FhWVw0KW+*A{@87BwEs5SOcLV z0qRzjna&+NH}5Jr=gR?@cI##va{`cb9-ODai|N+7ZKAV)lBlwHkhyi+hHWl!p@0N& zlvER73KqD481V!tgA(@d{jI z#$1HCwl!-RQIzgm(glct9~xphl>)-4-e;Y2T4c<*&$xh=Wh7Dw&M+fYo!lL83!@=x z_nLKSwhsP15Z%^pYk-uqQZOfBs(lsK2uobXw#7ggq%vR$iO?1N7Um}?4fS()>zhCG zW?|KSaJ{()A%GJ;j0f9cPS6?4Ydq|bk7yUzvy137QnPDcr?m61?i<2{WdJY2Eo&K) z@vR+}>B-3IV^)Bg)uLHM5z%Z55+X1$I0f9Sg;ydL8A?kD2oZY7?ZfxXeagG=rdkL# zwg4t6lB-vb$ehLuU}TNicFM>M-=kb2EznP6dXD=~V|ntIzVK1|(W9VG)^}caqUX== z4||jmLp0$!0WWZyp*b>%t|O$7Ram-Juu=pw%UL|)%qhZZKefIt(={SId^`fWx144s zW{PGFq-Qc200fBLYJ}yqV^$#{PPMNNy*qs1VeT%>Sr>xmw2O!=RCIPCGgD3!#3Qh$ zpQw-Uai5@<&g`9TV@4cNudr*-1^WXI2shv& zUpYzEqB03fH}j}lyDvJ839+zx*wzliQ~!v|kwF#h-V*aLN_Oi(N^qi)MIc1n`iiiU z_j0C+OsdOT4~Omb)(&PhOBv==X6@egWsivNEe56toH=t)uPY1zTc8Xm>Lc{qFR#_4R7G zCXf)SjcC1o=CFcV+Ze>b9LROx-FpTH>@{wG3C{`=V4wTNcmC1q+ds1uU;5S0fAqDF zj)+Up0~}xi8~TK4wZ3SX(&8g?5HTQv09hc3JbK;{@U0zkngUVsMYlRc!p+-g^X4=U zJFuu|GNppBlEP*hqlW29@>Rr}dL{J0=v4b}O zoDl+=pdaJKPveq76Xg2W-}~@SX_dbT>y17L^Tpe7|8cF`4i^FfrUTZ5a>8*!?qSB9 zB>`bkV+6-gVj>SSuO%%*wwENSltIZ7Nu&LhB;6i9nDfOzsnwljQ(R57wjmGhJ~#>P z5Znn)aCaxz5G=S35OfIc?ykXI!r<=iu7kTA&Ut^u+h2Bn=-O3#S6BC1>+ZfUnxTVT z6mkD8Lq25ek=f^PEX-m6xiD%tYo!BrQaw_6iz**BYCulBg6{NRVWjVQqgAfL_yr+n z2&g97^teG^IBz=cS>K~I{NmJnjvU_hLN^}sqaED?baT}oa=BXGmEU*b8EVr2zI4&n~nw z)2)!&u(2_T>u|_yew^*69Ql{e(P4+@nz7W2OoVXt^30qU{yP)f#N7xx#-7hz&ui6h z)P)Z#U60Q9#&3sIq_{tVt#)yh;4OOPdV)E1%BuZgrhalm8KraZxf*Q?8ccBssJRT z0JM&Q@NT%`o?7H9NdFc#7r z_H0g$qwP6*0poB5p5L-j^{qXxA%b<~eY_I6s>ol0ZkhTl_|<&t($|8|wwVe#TPknlmY0%llh zmQmu(FxrY=Ss-W_WOa9SQL;|X7dmpN>BxGbSwP#E;Uj5M+iSjD}-L6(jY^cA+5(Q3g?Op7XHF zt1n|ucF-6Kg(Q{@Y#PB-3S<5CL^N6dwa)oh!at>$j`4d7jDpp)I}fiZb{tZ=r&?C~ zeMy!CaxSlrcby#Y;-(qKA;_^5IRYoSi{dC zySi}$6%Mf_D>4Gb!=hJMu$4WlGlUt9E4EdJ-i_)s2rTi05F>^g_H1H+hEO+ZLBm60ijo;8Su0A>4QO9uKF2 z%I_D)S9CAbomW1Izr1}qUh(c^&{D-P2&pU#f*MTJ^ZfN8o?WP@%}YfB<>U4%jkMM};3rCkMwV(ajGy6i)Qmdz8w z-H#|&>9XWceK--2&OSYpy?mPCR6x<28lLzNk!_!mhhbn`J6jixL^B$T2k91rD!RM# zzy8tzV4J!+m`I_W``{K;QuuEM; zO}N_bWqVv|{i9b1;qgtUL|V^BJO+C=2rz!S#e}|{CSQsUoG6MSDOPW+XJ&N?(SMT_ zEI{P?~$7R=C%4qm|-amiGum-S?vq| zkL=o|x8gge6URzF%+M-=LBH?q=V*}}-EgjdiHTJ7lNBvX^IB*8x^M=Ys3`dxCbWb2 z)8tp{#;-4;56jUP$S*c0vb=(z+siGN023thU;dM18m1ApbeK9BRN$Un^|ZL%N{SGD z+ZxDrMwJZ5o$u#7T$={`&Cj&+BJ?@ytG=oB2n^;wJ^!-@ICe*^7|P-PW#4rClH?4H z!2KJ?b3*D;ao=i_^Ph;Rnk1~S81g0trf4wT`|!r|M~3;FpWTjka`mGH^jd3=Tc1aF z@n7Sg5_YjtH(8GERUUSecv?y{jt3YrBr6MS6ijHol@vr0+we!}>*3a>LPl%D`TWyR zh4LQbQAHeO`#lSS@hoq*@~u7Nf`kWu9x@@qvQll_VZaP`}EucgD z$Nnpt?HX_Ic8>4m)JgR*;?>Q{!XuNFeu3C0@_&XrOyb=ne|M)IH+=*LK9|U9s5*Uh z5$n|n*(5&rY{_4Ho-2NC6BDQDq_z^TX@|W%aqfHJl)NAH8#=nM>l4Id|U&cUffI&Ox@)rQmFuz3KlCbM*UJ{ldu$M-%aY7obe*Lpc z-!^L+Mhl1{Qp92E%43O9rlUDpo;_V+|~PowAM zCmgaRz~mDxz=hFvMjlUBW9E-+par_Jjy~dCOKJb*;O$IG+ZS`FP@rjftX9@=+~Y7} z+{-}c1gl%oHq1K-RJ)dOL;KaMJ8hNK$TO{3sRmag2oIdT(ifH-xh?k(!M~hR5KNK- zVq1*&Y1ek%UjSJh*NVk5onPE}-+Yy;jb5IFqbqE>30wsG<;YS6TGOzt%1{Kd6$N6= zqzs|KY7yWxO**B0NBk6JZnYuskPtnqAFC7tLt^-diPvpa=9PWgxRk_jFP~w75W>cU zQC>sT9MbXE^!snXu-IQj)6#01k|nU{5BTfmbj(IurzTTAN0;T*cTAV!zj(Lr=8yJO z=k-GZ84TF@G^R|jnJ9JpGzV#r8_6alB^%Bp1osU|o|cHlOD7r#n3N1zcSspZ^9r?i z-Q&MB>@!4KBFu;IJna4a!HCoEQnq|n#97U{z@O*I$j!@IQj*fLw9ux*%AZhFqzXIQ zi;bE~I=xzeTj5>rd$+qgm$WSt-GTM#MS4{YEu2f-DU6PMY?T*-oThIX&V=A!H~1EvzY^NveM2{O1M1=?3bo{0}^Z&QRiNkp-bWrK5nbHejzSt%8^rftg@UoITOApoZB>AL&_N#DdAxP@V z<_f53Fid8W>yPI<(I>VoFCK68U*3Yf)HDL^yL)5iV2MDt7QYzO&_j^AZW|^>A}) zZR;0^#o@+MT4FtdU-(LdEEu8hBkuP-D6rRI_+) z-*9Hy${d_MZAs3FS@jioF=pvreW}_IsnpTWb7OZH_+%iDOVEG@7I3=e4;V0&E)|Ke zAU4a@C_)g3dv_j>Jz4nHzXIGc!Z>?OmhQ)xQ?caSg>Zf?>i9WmZ(QAH>1+u@{4&Tg)ubQR0FM znBwc5IMT&!+syXx!>#`Pde5b#TXP_BUv3Cr;GEhBA3I)opBjTrJddGHSk88ZQePPu zY_ROtUxUV~Q4Z)`W34(UlG7~CJ2n7lYt5XB)g4DwP@BH_6Xh9Ex3ag<%61MT!) zYaMsG2BkoxeMwsur3_h&oNXY>`7fQArOdzO=j$G=`z6HzcvD%6xnyaJLc=}VPVW>L zM$bTZ63ptGHt+i;TjCxRf^hh74>8KhYSXw~Nlwe8z=#zWSR6x_dUg3t3oQqBR|1L<%x0J zE1s>^VZw@%dXlj;U;m{wi&H#a-X5$r5tF{mqrF~k7-sqGuRA+zU%&#W+`7dbzvX(g zv%#{_T3S;GV0REI4+zzFrjsG$+5XCexPldIR&E!7MCJyWc1GtbxcCfV>Y|}zJh|0c zfwme38>Bjll-u0n67WVZ8g8>wwim<|1iS-=_)Pq|wFz~U@QdErcJcYW$h$9+Pd1N?{CiB{GA{aX@GuX3GE)b5RiB#)WnN+ViWWui zxb*P$*4u~|Z!^+XX#&y8ug@wwg;kyU9JlkLwIc2#Q{gExQNiQByh=MhOV-y9IW&ky znRAS^g<4i-EsHvpSd%D;rc&;b2PL+vno$&vcQ>LhL&`pnEei%<3Yt4{kD=Xp-l(gH zCgp4sO$L41(5^8XWyI;}@}sKLJRT$8#A8X`nP4%O9ti(bi*3IxJMhB_H!rfaU(lgM zRjy%?S-8KQtb)He1n7L?!*DdsPa#@Zw@KOHxNMq5@*WxF#>m$3b_3T^H1Yt zb8$2yp3C);GGFEVVa8T}Dz)?kkRPzEw_h6iF@@Y6uAz4NL2r;T#uqIs=saGMdU6wi z4PMtptYzR5K$Bv+#!L$Dwb@{4cJx3#6c)M+<{1muEp0gTu_IUz!K3$H_ z2$g5!f;_L6oAHNy?9Un!4P`0dCV^L1@2+4^zXgTKM~`oc%mC5aa&?(75E<*%B*uon zIHK~)Y(7Zs8Crxf;d|Eieq{Wz3w;TlpqS(>G1c#n#X%naxu<1Y6>jhqKQDqZZTQ1F zkE5zqlWzRk-o6p%mT`(X{Hch4$TI?80!z~_50jDDH>1c|jCjL5`N(_@Z8Y2&uR1^v z{=hL=m`nFn=X~jvfNe0aChy2G_z1;U>d)n2arV=71hn4nSSG6j>+St#Z;zMfVvs?z(%7=ySiQ+6Xc9z8SZ0K3QL)x}j3fyMt@_nF}YYpicCgi;{qwr)p*2PRe`Z zbegu=Qpx_4il}}-ShE>EoRgt<%(c#F$fe8h%4V_(JoaTs0f!MMmSDkUA<%|szc!h-6 z*%>6I9QKpi)D-nw;v~~Ad5M#)>rg(J;>s+|96s5!1>aL^|+&4O)IjT@;54pbVNpY)${z}c04waQ+qM=DY4#`v_ zo5ubGH!BNkQ&WB;0|knb8SNzYfQF%>?oS(UtML@CF9+G1Kd2kvLVuL?M*gWI%bWw- z(4a~#aCO@F^3LNJj&kqmNosKOxel(%?7?vs5Jv2GcPqH{W&$nbBo;^;bE_>fs8+x< zboPTYZa$L(4T*S?eaw_JRHYDV_ZCp1xs;v{93}=vSQJo!4%+g#x8P!Nkw0vN^p0Te z>{Hv>?Cb8G*{H(dtX!ndHA$;hI1AjB&wej7hFd7m3zU}X=kQt>)wQluZ3yF=+SKn$ zwW!;cY_|oNhT})~G8PezdzKes%2%&3vL0B*7|4wc$yJt0Uc)X-b3Y)#+6|#2)k1{j z(%;V$yB6EQ(#;NInMJ-UvBJ*JZ{`(nD{(x30%A&W%_UZ_1_b0R*D2gPBZ>c%;SBp& z=Zhq(N?KB+ZW80)j+;B17+}|Ju1M+VDo(-I0cmw?{&6%f2G1q9pX{puS&FncG`Z=< zdSo$17Srr|#OdYR)zI2{wwh%fp0&H4{!aKj-ZJ(%I$kyQ8+kf9DOll|49rfWq2++7 zaS{z=uuHXm^QiWXYPbq!mLgzhUuj8Z@_cjr`edn;$7Yd{4$ZgCM>W&z+l!MluXLRv z4Ie5KBr1v+cNYsxqqzQ7S^!*<4vETy$O0#7i8M_(19WbsIXm_-F=@xxk z`Z(tXpS}7O{V;A{1c0j7%g7y%qs~IJWF6w@nZ+NS<529Z356u5?GIvLJ5i4J@zXNw zW#U4)>pNZZz`A|k>ev1hM|kkD~M`lZtk1JiWJWMOy<&_jsShjgNd|J$~qZXN#Zt8Z%6qC<5IdP8iWSNfv6y2ys)~=L% ze6cf~3e>muaEtjqRot1s^a#ypd%Yr)e_!obQLd?)+>z#y({M3!;mb7SiQwm&8yc@;E%u#16z4QzIV*_oT4mmAm5XD~bLi<&M&2DU%yB%9yL5B+tIma8CO919t|7 zY%Eaf8-NQ#t6AaKU_SG%jracWNl_r@M28F1>TN6Z?TSrw;0I#RC;8z!juS>W7fPm{ zbZ03^>V@xp5azk>)Qx_~ntc<=HZ2N-g-VQm!}>iyMI*=NmH=6{S8>~uWHatoOWsT} z2oxv#rg&s^=Ywr|WOYJ7B>>(I>F8p-#AaF1Jk2> z^94t^g%Uh&^<2rV1^kkV|5vZl)jZDIdw}In+3Wxjv)~Ll}Y8kauMUn5yvBV#v8Oca8 zWa7E^`ZJ5iE$!3?yeZcxQltCoybZ|J=BzW*#CX~2bD5B9NGK(60>jbovH%e4ZPRE( zOkkCCIxffHvP0f?A zel|s8B#W9xwcW;NBsv9p>K}4uTYof4*w&g6X{bGbu6OnPn*{S8OX^Mus$_g7XVX+8 zD&Z0Q?e15}eIPIoG?J*a;4wy!BdSzV&Bsk;8_GK=PgFb6>7VC@z0EV@*qchVc4ZAs z=_7)Tgve$LqQm`&WTQruX>M{(biWLq%io9)@Hq=^bK3(F+1rIoeX-TT$F2}FVZ;g# z@tD=j9?_}va-!{YuAJrC73(YHfQxi4D4gTii{!i}ZkMfEvZcqTUnes_yZ2h)S8%F( zCDt0!l+M+#YRox8-V`u{Fx7q&pvHmo2A@A1RJ~5QyR$uvJ&c}R3PYy=omZO(Be6cg z_$o2v3*D03z=Dy2syjT%+3#UhqS@!^sl1x2~a&Z4+qslOP1(|PGkYgQDt4Ks>E1OjEEj;bc3MeRUZ}gjdoWhau}DVxq|#xINWXmT_JzZ>r3)`ZkUDHXL7`xFsvF( z=4`P_XqA4qxr7ahtw@uwDLKvl(Bzqsl49C1Xe#s~1bh z-~Kq;1MTD&aeor#Le5xbdf$5{f8I^b0wE5-3#1M6#e4?HLA=d+gv2fzl5|?7eYmrM z3|buzC8ikiIFN8Anh*I&;L^Fv_-hl!$+vEB%J;eFo!2jRZZmzg6&03LynIw7_|vfE z_EyFlG2UZW!yib|mHVh8e2{$D=7_fD*p6;q!f`;gfXf zY@?gv5xcG73H9+R{!cTleg9ImxH;0-T)k9@KkCceRrlK@Hd=nAmTD}CttPSRjPW*! z{`azyBznP;E#eu2s4B;4ZUK-&W53-@kkeb4RRjgjo%n;I=hoa*>h~xL8ldpGtt~&aQMNb#gO1 z17yI?k`Aw}KHFjBrv|DIEvY_;+fG8Tw&S}td!PNU+9$zs<)N+nTs*+mCI#qXKilUv zI3LIRUz|ypgs{EX4wh6f+VV90v0Mx@O|pheWfVVCZ=kNzhhqtcS33~{X67BNv2%l3 z!xNVx$FirdqqR(yJVPe@gz3laMy9k6-l^a;_wqd}MUycQbf7OI->&rMb!f$59$?h& zKRr{0Bp5d!VK@a>Zx(jDth|Ert4hoE z`%s}JH+Ooi{$gHgQ-}s=sW6qy{<{vRam)hMlf=^=I_PRbp^7RJ&*3LQPDD07vub6Y!`Iuu6%NN5i>uqs&!CoDhF$5b z`6q1%Um&lW#Rzx=AIX(!`U8j+kYzcROI0};7P+XIR=n;LZ|u9`0NQ5j+9+&(9=x}vngq}LDOe)Ttuk#URt+)TFb2zCw%NEi&yYZf08kUZijjhX+Y0ld;=;;D_S z$8NG9l_oWwyn!lDpEcG#EQumH_=U>L?$gFzPoGVh!353hTM zfN=D4e76HMrYEu=z(CGM`Bt*VAF4Isxw)Y3)ZX74jv{oH8Vrfc@>XGcXg_FWR1CT| zwu3`DY0wm~othE4%r6e(7O{j&=?H84h5Mf7qoa+(s>c=1+YXYel9fR>)m(|N3;z&) z?;a_!y~7#&7UQEsrJ3emMz?~;%Vxk;?@mv%`C2Y7T&5*Q4p)iih;i;j`-g?;3u2%Q zPCljlKcX3YuYCG>TpYJBZ@|E##2E$p^L&a!ub<4r+0w&rcOR46(KYR;CcADKE)^y% zwhmkKK+bVYo9<7jR5Atm`Wkbeo zDHgUo`YIc}EnUP^L3$NI;dPupFt*SYk-NDtYNPZ1g6JRwIyuj8J7=AVCygpVFYUpD zr!*aLGw}*?&2tHobu5Yfk1-*9ZFs&#NzslSOcM-AU?5>-+~H4`oxw#>M`U^loSdxG zp(iH7hyiogM>}2Mf}pV*IevSO(4oT3CI+dlmrdoniB6Ab4gHrdUsT7J?wVsy9R+Li zB?DEM8VY|4eRboavcj;b(5zc00M4dmrkY+m{iMD(9y{6UHHRITc>MOH&5XY?6>*ms6AM(h&GfD z9-zt~%UTp7B5AY%vt8vrq)e-@Na5IKpL8wUbh|y@S*PGWjI!UO$9`ku{nI|OX746`kz_zBK;rjpUwxc0M_HLL)b39pdXAUQK=8CZdePnZ%W^QPL6rptiyk z{|Nr3Ar8q_b^GbQ8<3kDK8oRKCMyvy+csiX&$pWq!Tl<0kJUS0k6V~Ok^ny^%S4SU zbnZW=zrOK$hbc|5Ip#glaW%S+-5R*Mf9fwqsql0BE9Tpkw~;c@CoRYSJcodv;awVe zDiY8E!Ng9%ltIJvC8`8)Sc9O~8LZzVCI2wW7iSDeHo9I7UhOOY>-1jtJ?qgHeN=0f z?_RUg+azEX^6T|TS1d?nQ^9=c1v-XJfMRQ&S`t{@elv$3U znG!f$B~)%ffaa61#OZC;8u-ds6oxO??|KnTv*LHna+mc{W2O9HJF=u@qMBQ4;#J!KNj8Lx>_;Nbm?AyRdm(_dVQ& z@R%e@35QYc*Me@G``LzpQ@V$>1@E~3t8jKolQ#j3o`(CTQVB1EEB5+sIf;&cz7_QGJts!Jk5r(@79HXj;;uGp-+gN)auI_jSy_~VN zPdU6Oeqcmw9)B5+yN6IL61l~@(i*8Sd43i&DEeWIbiai1$)?~GtFS`1!iM*!SDI`I zJ9{G}!0sE$QOs?8&|sOTanr+OeAguuj1}po@FcvZTiMneD0&k4oHhjDc z+100euhsy8Y@!<%RPj7M7c(?Iu`k{~#Ij5O)kA0@TiN?SU*_hfB2f|0SyU}1=SMN7 z>VXd0bqN4HELDSUwFDocYRvyY0xo0rU#9B?9Eb#5zD*DUf{;1oT7Et&ktvymclFjt z;+H<~I&m9QWceI8y<8xIcHW;LB(F&u*zenGYXcuZH$ayU)Mox*7u!8hI42{PY8@9r ztq8%V@YB(B^MJsMkm=$Uj2J?{0>9~;NwiZ&b`{j;VCens3Uhw`K>uRv&$TOUpjJ{n&6kN1by{mR?s&P3-F z^oIEH*1hrlJRa2PEp==okjFdhBS>jY>1iO(Hp|)nUs}L%i8NVB-K{B2MvX|3peNMK zoy+&;Ce-8V2v9X^)%i4hmOTCu29Z;!_9E17!)4MlZAVcz2h>AIR?Wj?-p@1qpZLI_y2VXSXF4%y*^3dLyV2S|n zVI+)c+HMxz@wj`qM)!V@-GRYc>wwht!t|c{0iX1{ly`UV@qN`aq96QbF}|4R?Im#1~Pb_TQOnl>v?5(?v7rTCi%}Z+HA-(?vXK-3?9nSi#?3+@bofE6P51 zFGf+nlLRe#YjQFpFK~ybgfCfFLNvSN+&p5ERxrD+&zhqCIlLbI=6zZ+wt5@V?=61Y zZuynPTikZ`I=htwQE+AF2pBp1im2ZR?Yv8>?*w%w6lXU#K9*)bHoZ?kyQU`I1g>qB z@0zmOULOJW?h=L@2U7hA4uoO3@NGS=C7};>DL37}-^g!BP^D1#_}x-Lo310~=QvTj?q#yQ^C=D@cYC`o*4?~}3RBZgx~`!j zuhOF9BtvX3tI-tjys7AGJ literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Reflectance-with-IOR.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Reflectance-with-IOR.png new file mode 100644 index 0000000000000000000000000000000000000000..fb5755a7ef3fa3f0d3918be38327e328d4a4ea95 GIT binary patch literal 56791 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

k~Mc03JCqI!7 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

-g@pW-juJV?V6IsCnYs#V6?A7MXuv?Upns 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 Z0dQ^pOnLX$NCIA(nv#}ct-NLEe*kPH?jryI literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-Weight.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-Weight.png new file mode 100644 index 0000000000000000000000000000000000000000..2179c39263ab39cfae89412e708e2e38ffd74602 GIT binary patch literal 115904 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

!iDbTF#0lXkbZ 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 literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/config.json b/packages/tools/tests/test/visualization/config.json index ce0e002de93..e39dfe30045 100644 --- a/packages/tools/tests/test/visualization/config.json +++ b/packages/tools/tests/test/visualization/config.json @@ -2756,6 +2756,46 @@ { "title": "Test code inlining", "playgroundId": "#YG3BBF#51" + }, + { + "title": "OpenPBR IBL Reflectance with IOR", + "playgroundId": "#KQYNYS#46", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL F82 Specular Metal vs Weight", + "playgroundId": "#GRQHVV#25", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL F82 Specular Roughness vs Weight", + "playgroundId": "#GRQHVV#26", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL Furnace Test for Metal-Rough", + "playgroundId": "#KQYNYS#47", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL Specular IOR vs Coat IOR", + "playgroundId": "#GRQHVV#28", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL Metal vs Coat IOR", + "playgroundId": "#GRQHVV#29", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL Specular IOR vs Coat Weight", + "playgroundId": "#GRQHVV#30", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR IBL Specular Roughness vs Coat Roughness", + "playgroundId": "#GRQHVV#31", + "excludedEngines": ["webgl1"] } ] } From 2bdb407d1d546b3e6203623df0f492b39db21e6b Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 30 Jul 2025 13:19:28 -0700 Subject: [PATCH 27/45] Revert settings.json --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c2d94cb8798..375867ba018 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,7 +50,7 @@ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.formatOnSave": false, + "editor.formatOnSave": true, "jest.runMode": "on-demand", "typescript.preferences.importModuleSpecifier": "project-relative", "javascript.preferences.importModuleSpecifier": "project-relative" From 6a284da02af89f55ecd91e536f7bab484e5b58d9 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 30 Jul 2025 18:51:15 -0700 Subject: [PATCH 28/45] Added OpenPBR inspector data and WIP on coat noramls --- .../core/src/Materials/PBR/openPbrMaterial.ts | 47 +- .../IBLShadows/iblShadowsPluginMaterial.ts | 8 +- .../ShadersInclude/openPbrUboDeclaration.fx | 6 +- .../ShadersInclude/openpbrBlockNormalFinal.fx | 19 + .../openpbrDirectLightingDiffuse.fx | 5 - .../openpbrDirectLightingInit.fx | 2 +- .../openpbrFragmentDeclaration.fx | 22 +- .../openpbrFragmentSamplersDeclaration.fx | 2 +- .../ShadersInclude/openpbrGeometryInfo.fx | 2 +- .../openpbrNormalMapFragment.fx | 5 +- .../ShadersInclude/openpbrNormalMapVertex.fx | 2 +- .../openpbrNormalMapVertexDeclaration.fx | 2 +- .../openpbrVertexDeclaration.fx | 11 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 33 +- .../dev/core/src/Shaders/openpbr.vertex.fx | 8 +- .../ShadersInclude/openPbrUboDeclaration.fx | 2 + .../openpbrFragmentSamplersDeclaration.fx | 2 +- .../core/src/ShadersWGSL/openpbr.fragment.fx | 8 +- .../core/src/ShadersWGSL/openpbr.vertex.fx | 6 +- .../tabs/propertyGridTabComponent.tsx | 3 +- .../openpbrMaterialPropertyGridComponent.tsx | 568 ++++++++++++++++++ .../pbrMaterialPropertyGridComponent.tsx | 20 +- .../KHR_materials_emissive_strength.ts | 10 +- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 2 +- 24 files changed, 710 insertions(+), 85 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockNormalFinal.fx create mode 100644 packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/openpbrMaterialPropertyGridComponent.tsx diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index b86081e9a27..d28e62031e1 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -625,6 +625,15 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _geometryNormalTexture: Sampler = new Sampler("geometry_normal", "geometryNormal", "GEOMETRY_NORMAL"); + /** + * Defines the normal of the material's coat layer. + * See OpenPBR's specs for geometry_coat_normal + */ + public geometryCoatNormalTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "geometryCoatNormalTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _geometryCoatNormalTexture: Sampler = new Sampler("geometry_coat_normal", "geometryCoatNormal", "GEOMETRY_COAT_NORMAL"); + /** * Defines the opacity of the material's geometry. * See OpenPBR's specs for geometry_opacity @@ -643,6 +652,15 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _geometryOpacityTexture: Sampler = new Sampler("geometry_opacity", "geometryOpacity", "GEOMETRY_OPACITY"); + /** + * Defines the opacity of the material's geometry. + * See OpenPBR's specs for geometry_opacity + */ + public emissionLuminance: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "emissionLuminance") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _emissionLuminance: Property = new Property("emission_luminance", 1.0, "vLightingIntensity", 4, 1); + /** * Defines the color of the material's emission. * See OpenPBR's specs for emission_color @@ -656,10 +674,10 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { * Defines the color of the material's emission. * See OpenPBR's specs for emission_color */ - public emissionTexture: BaseTexture; - @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "emissionTexture") + public emissionColorTexture: BaseTexture; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "emissionColorTexture") // eslint-disable-next-line @typescript-eslint/no-unused-vars - private _emissionTexture: Sampler = new Sampler("emission", "emission", "EMISSION"); + private _emissionColorTexture: Sampler = new Sampler("emission_color", "emissionColor", "EMISSION_COLOR"); /** * Defines the ambient occlusion texture. @@ -682,14 +700,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { @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. @@ -967,13 +977,6 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { */ 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. @@ -984,7 +987,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { /** * 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); + private _lightingInfos: Vector4 = new Vector4(this._directIntensity, 1.0, this._environmentIntensity, 1.0); /** * Stores the radiance (and, possibly, irradiance) values in a texture. @@ -1317,10 +1320,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._coatRoughnessTexture; this._coatIor; this._geometryNormalTexture; + this._geometryCoatNormalTexture; this._geometryOpacity; this._geometryOpacityTexture; + this._emissionLuminance; this._emissionColor; - this._emissionTexture; + this._emissionColorTexture; this._ambientOcclusionTexture; } @@ -1781,7 +1786,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // Misc this._lightingInfos.x = this._directIntensity; - this._lightingInfos.y = this._emissiveIntensity; + this._lightingInfos.y = this.emissionLuminance; this._lightingInfos.z = this._environmentIntensity * scene.environmentIntensity; this._lightingInfos.w = 1.0; // This is used to be _specularIntensity. diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts index d5f886cbb99..6b205efc2bd 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts @@ -170,11 +170,11 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #ifdef COLORED_IBL_SHADOWS var shadowValue: vec3f = computeIndirectShadow(); slab_diffuse *= shadowValue; - slab_glossy *= mix(vec3f(1.0), shadowValue, alphaG); + slab_glossy *= mix(vec3f(1.0), shadowValue, specularAlphaG); #else var shadowValue: vec2f = computeIndirectShadow(); slab_diffuse *= vec3f(shadowValue.x); - slab_glossy *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, alphaG)); + slab_glossy *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG)); #endif #endif #else @@ -248,11 +248,11 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { #ifdef COLORED_IBL_SHADOWS vec3 shadowValue = computeIndirectShadow(); slab_diffuse.rgb *= shadowValue.rgb; - slab_glossy *= mix(vec3(1.0), shadowValue.rgb, alphaG); + slab_glossy *= mix(vec3(1.0), shadowValue.rgb, specularAlphaG); #else vec2 shadowValue = computeIndirectShadow(); slab_diffuse *= shadowValue.x; - slab_glossy *= mix(pow(shadowValue.y, 4.0), shadowValue.x, alphaG); + slab_glossy *= mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG); #endif #endif #else diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx index ebcbdd8e31d..1324c6c1c15 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx @@ -91,10 +91,12 @@ uniform Material { mat4 coatRoughnessMatrix; vec2 vGeometryNormalInfos; mat4 geometryNormalMatrix; + vec2 vGeometryCoatNormalInfos; + mat4 geometryCoatNormalMatrix; vec2 vGeometryOpacityInfos; mat4 geometryOpacityMatrix; - vec2 vEmissionInfos; - mat4 emissionMatrix; + vec2 vEmissionColorInfos; + mat4 emissionColorMatrix; vec2 vAmbientOcclusionInfos; mat4 ambientOcclusionMatrix; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockNormalFinal.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockNormalFinal.fx new file mode 100644 index 00000000000..62de4c4fb29 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockNormalFinal.fx @@ -0,0 +1,19 @@ +#if defined(FORCENORMALFORWARD) && defined(NORMAL) + vec3 faceNormal = normalize(cross(dFdx(vPositionW), dFdy(vPositionW))) * vEyePosition.w; + #if defined(TWOSIDEDLIGHTING) + faceNormal = gl_FrontFacing ? faceNormal : -faceNormal; + #endif + + normalW *= sign(dot(normalW, faceNormal)); + coatNormalW *= sign(dot(coatNormalW, faceNormal)); +#endif + +#if defined(TWOSIDEDLIGHTING) && defined(NORMAL) + #if defined(MIRRORED) + normalW = gl_FrontFacing ? -normalW : normalW; + coatNormalW = gl_FrontFacing ? -coatNormalW : coatNormalW; + #else + normalW = gl_FrontFacing ? normalW : -normalW; + coatNormalW = gl_FrontFacing ? coatNormalW : -coatNormalW; + #endif +#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx index 6ad4829f021..6d7b7eef180 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx @@ -1,11 +1,6 @@ #ifdef LIGHT{X} vec4 diffuse{X} = light{X}.vLightDiffuse; - // Diffuse contribution - #ifdef SS_TRANSLUCENCY - info{X}.diffuseTransmission = vec3(0.0); - #endif - #ifdef HEMILIGHT{X} info{X}.diffuse = computeHemisphericDiffuseLighting(preInfo{X}, diffuse{X}.rgb, light{X}.vLightGround); #elif defined(AREALIGHT{X}) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx index f82a624f71d..dd928b04214 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx @@ -1,6 +1,6 @@ #ifdef LIGHT{X} preLightingInfo preInfo{X}; - lightingInfo info{X}; + openpbrLightingInfo info{X}; float shadow{X} = 1.; #if defined(SHADOWONLY) || defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}) //No light calculation diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index 7573018c212..6415f95ce4b 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -1,16 +1,18 @@ uniform vec4 vEyePosition; -uniform vec3 vReflectionColor; -uniform vec4 vBaseColor; uniform float vBaseWeight; +uniform vec4 vBaseColor; uniform float vBaseDiffuseRoughness; -uniform vec4 vCoatColor; +uniform vec4 vReflectanceInfo; +uniform vec4 vSpecularColor; +uniform float vCoatWeight; +uniform vec3 vCoatColor; +uniform float vCoatRoughness; +uniform float vCoatIor; +uniform vec3 vEmissionColor; // CUSTOM CONTROLS uniform vec4 vLightingIntensity; - -uniform vec3 vEmissionColor; - uniform float visibility; // Samplers @@ -35,12 +37,16 @@ uniform vec2 vGeometryNormalInfos; uniform vec2 vTangentSpaceParams; #endif +#ifdef GEOMETRY_COAT_NORMAL +uniform vec2 vGeometryCoatNormalInfos; +#endif + #ifdef GEOMETRY_OPACITY uniform vec2 vGeometryOpacityInfos; #endif -#ifdef EMISSION -uniform vec2 vEmissionInfos; +#ifdef EMISSION_COLOR +uniform vec2 vEmissionColorInfos; #endif #ifdef METALLIC_ROUGHNESS diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index bb2cd15c86c..818262b6cac 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -8,7 +8,7 @@ #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) -#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) +#include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_SAMPLERNAME_,emissionColor) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx index f7c2a48f0e1..7bd351efa69 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrGeometryInfo.fx @@ -26,7 +26,7 @@ geometryInfoOutParams geometryInfo( outParams.horizonOcclusion = 1.0; #if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) #ifdef HORIZONOCCLUSION - #ifdef GEOMETRY_NORMAL + #if defined(GEOMETRY_NORMAL) || defined(GEOMETRY_COAT_NORMAL) #ifdef REFLECTIONMAP_3D outParams.horizonOcclusion = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx index f0b780f1c82..6083fc4ae51 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx @@ -1,5 +1,4 @@ vec2 uvOffset = vec2(0.0, 0.0); - #if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) #ifdef NORMALXYSCALE float normalScale = 1.0; @@ -48,6 +47,10 @@ vec3 detailNormal = vec3(detailNormalRG, detailNormalB); #endif +#ifdef GEOMETRY_COAT_NORMAL + coatNormalW = perturbNormal(TBN, texture2D(geometryNormalSampler, vGeometryNormalUV + uvOffset).xyz, vGeometryNormalInfos.y); +#endif + #ifdef GEOMETRY_NORMAL #ifdef OBJECTSPACE_NORMALMAP diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx index fe467dd1c3a..66ea1a3a889 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.fx @@ -1,4 +1,4 @@ -#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(GEOMETRY_COAT_NORMAL) || defined(ANISOTROPIC) #if defined(TANGENT) && defined(NORMAL) vec3 tbnNormal = normalize(normalUpdated); vec3 tbnTangent = normalize(tangentUpdated.xyz); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx index 12b795200ee..2441ca7d786 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.fx @@ -1,4 +1,4 @@ -#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) +#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(GEOMETRY_COAT_NORMAL) || defined(ANISOTROPIC) #if defined(TANGENT) && defined(NORMAL) varying mat3 vTBN; #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx index 3dfa76671f8..3a39d06bd5c 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -31,9 +31,9 @@ uniform vec2 vAmbientOcclusionInfos; uniform mat4 ambientOcclusionMatrix; #endif -#ifdef EMISSION -uniform vec2 vEmissionInfos; -uniform mat4 emissionMatrix; +#ifdef EMISSION_COLOR +uniform vec2 vEmissionColorInfos; +uniform mat4 emissionColorMatrix; #endif #ifdef LIGHTMAP @@ -61,6 +61,11 @@ uniform vec2 vGeometryNormalInfos; uniform mat4 geometryNormalMatrix; #endif +#ifdef GEOMETRY_COAT_NORMAL +uniform vec2 vGeometryCoatNormalInfos; +uniform mat4 geometryCoatNormalMatrix; +#endif + #ifdef POINTSIZE uniform float pointSize; #endif diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 1d338e65d02..9396f727733 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -2,7 +2,7 @@ #define CUSTOM_FRAGMENT_EXTENSION -#if defined(GEOMETRY_NORMAL) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) +#if defined(GEOMETRY_NORMAL) || defined(GEOMETRY_COAT_NORMAL) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA) #extension GL_OES_standard_derivatives : enable #endif @@ -68,6 +68,16 @@ precision highp float; #include #include +struct openpbrLightingInfo +{ + vec3 diffuse; + #ifdef SPECULARTERM + vec3 specular; + #endif + vec3 coloredFresnel; + float fresnel; +}; + // _____________________________ MAIN FUNCTION ____________________________ void main(void) { @@ -77,10 +87,11 @@ void main(void) { // _____________________________ Geometry Information ____________________________ #include + vec3 coatNormalW = normalW; #include - #include + #include // ______________________ Read Base properties & Opacity ______________________________ #include @@ -110,7 +121,7 @@ void main(void) { // _____________________________ Compute Geometry info for coat layer _________________________ geometryInfoOutParams coatGeoInfo = geometryInfo( - normalW, viewDirectionW.xyz, coat_roughness, geometricNormalW + coatNormalW, viewDirectionW.xyz, coat_roughness, geometricNormalW ); // _____________________________ Compute Geometry info for base layer _________________________ @@ -178,7 +189,7 @@ void main(void) { #else vec2 reflectionCoords = vec2(0., 0.); #endif - reflectionCoords = createReflectionCoords(vPositionW, normalW); + reflectionCoords = createReflectionCoords(vPositionW, coatNormalW); float coatAlphaG = coat_roughness * coat_roughness; coatEnvironmentLight = sampleRadiance(coatAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) @@ -276,7 +287,7 @@ void main(void) { } #endif - // _____________________________ Direct Lighting Info __________________________________ + // __________________________ Direct Lighting Info ____________________________ vec3 baseDiffuseDirectLight = vec3(0., 0., 0.); #ifdef SPECULARTERM vec3 baseSpecularDirectLight = vec3(0., 0., 0.); @@ -296,7 +307,6 @@ void main(void) { aggShadow = aggShadow / numLights; - // Handle direct lighting vec3 finalDiffuseDirect = baseDiffuseDirectLight * vLightingIntensity.x; @@ -310,17 +320,16 @@ void main(void) { finalSpecularDirect += baseSpecularDirectLight; #endif - - // _____________________________ Emissive ________________________________________ + // _____________________________ Emission ________________________________________ vec3 finalEmission = vEmissionColor; - #ifdef EMISSION - vec3 emissionColorTex = texture2D(emissionSampler, vEmissionUV + uvOffset).rgb; - #ifdef EMISSION_GAMMA + #ifdef EMISSION_COLOR + vec3 emissionColorTex = texture2D(emissionColorSampler, vEmissionColorUV + uvOffset).rgb; + #ifdef EMISSION_COLOR_GAMMA finalEmission *= toLinearSpace(emissionColorTex.rgb); #else finalEmission *= emissionColorTex.rgb; #endif - finalEmission *= vEmissionInfos.y; + finalEmission *= vEmissionColorInfos.y; #endif finalEmission *= vLightingIntensity.y; diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index f04693f9aac..2de8d10f6ad 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -43,8 +43,9 @@ attribute vec4 color; #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) +#include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) -#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) +#include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) @@ -224,9 +225,10 @@ void main(void) { #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) + #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_MATRIXNAME_,geometryCoatNormal,_INFONAME_,GeometryCoatNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) - #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) - + #include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_MATRIXNAME_,emissionColor,_INFONAME_,EmissionColorInfos.x) + #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_MATRIXNAME_,ambientOcclusion,_INFONAME_,AmbientOcclusionInfos.x) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_MATRIXNAME_,detail,_INFONAME_,DetailInfos.x) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index b0e32a9abac..5966717b64d 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -67,6 +67,8 @@ uniform vCoatRoughnessInfos: vec2f; uniform coatRoughnessMatrix: mat4x4f; uniform vGeometryNormalInfos: vec2f; uniform geometryNormalMatrix: mat4x4f; +uniform vGeometryCoatNormalInfos: vec2f; +uniform geometryCoatNormalMatrix: mat4x4f; uniform vGeometryOpacityInfos: vec2f; uniform geometryOpacityMatrix: mat4x4f; uniform vEmissionInfos: vec2f; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 5bdeb89db97..6357f820f3c 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -9,7 +9,7 @@ #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) -#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_SAMPLERNAME_,emission) +#include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_SAMPLERNAME_,emissionColor) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_SAMPLERNAME_,decal) diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 2bc850fab5f..49da7c0249d 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -292,14 +292,14 @@ var specularColor: vec4f = uniforms.vSpecularColor; // _____________________________ Emissive ________________________________________ var finalEmission: vec3f = uniforms.vEmissionColor; - #ifdef EMISSION - var emissionColorTex: vec3f = textureSample(emissionSampler, emissionSamplerSampler, fragmentInputs.vEmissionUV + uvOffset).rgb; - #ifdef EMISSION_GAMMA + #ifdef EMISSION_COLOR + var emissionColorTex: vec3f = textureSample(emissionColorSampler, emissionColorSamplerSampler, fragmentInputs.vEmissionColorUV + uvOffset).rgb; + #ifdef EMISSION_COLOR_GAMMA finalEmission *= toLinearSpaceVec3(emissionColorTex.rgb); #else finalEmission *= emissionColorTex.rgb; #endif - finalEmission *= uniforms.vEmissionInfos.y; + finalEmission *= uniforms.vEmissionColorInfos.y; #endif finalEmission *= uniforms.vLightingIntensity.y; diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index 03832c9da64..d35d0e8aecd 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -39,8 +39,9 @@ attribute color: vec4f; #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) +#include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) -#include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission) +#include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal) @@ -212,8 +213,9 @@ fn main(input : VertexInputs) -> FragmentInputs { #include(_DEFINENAME_,COAT_COLOR,_VARYNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) + #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_MATRIXNAME_,geometryCoatNormal,_INFONAME_,GeometryCoatNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) - #include(_DEFINENAME_,EMISSION,_VARYINGNAME_,Emission,_MATRIXNAME_,emission,_INFONAME_,EmissionInfos.x) + #include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_MATRIXNAME_,emissionColor,_INFONAME_,EmissionColorInfos.x) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_MATRIXNAME_,ambientOcclusion,_INFONAME_,AmbientOcclusionInfos.x) #include(_DEFINENAME_,DECAL,_VARYINGNAME_,Decal,_MATRIXNAME_,decal,_INFONAME_,DecalInfos.x) diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index 4e3e537d2f2..0235400d2f6 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx @@ -21,6 +21,7 @@ import { MaterialPropertyGridComponent } from "./propertyGrids/materials/materia import { StandardMaterialPropertyGridComponent } from "./propertyGrids/materials/standardMaterialPropertyGridComponent"; import { TexturePropertyGridComponent } from "./propertyGrids/materials/texturePropertyGridComponent"; import { PBRMaterialPropertyGridComponent } from "./propertyGrids/materials/pbrMaterialPropertyGridComponent"; +import { OpenPBRMaterialPropertyGridComponent } from "./propertyGrids/materials/openpbrMaterialPropertyGridComponent"; import { ScenePropertyGridComponent } from "./propertyGrids/scenePropertyGridComponent"; import { HemisphericLightPropertyGridComponent } from "./propertyGrids/lights/hemisphericLightPropertyGridComponent"; import { PointLightPropertyGridComponent } from "./propertyGrids/lights/pointLightPropertyGridComponent"; @@ -400,7 +401,7 @@ export class PropertyGridTabComponent extends PaneComponent { } else if (className === "OpenPBRMaterial") { const material = entity as OpenPBRMaterial; return ( - ; + onPropertyChangedObservable?: Observable; +} + +/** + * @internal + */ +export class OpenPBRMaterialPropertyGridComponent extends React.Component { + private _onDebugSelectionChangeObservable = new Observable(); + constructor(props: IOpenPBRMaterialPropertyGridComponentProps) { + super(props); + } + + switchAmbientMode(state: boolean) { + this.props.material.debugMode = state ? 21 : 0; + } + + renderTextures(onDebugSelectionChangeObservable: Observable) { + const material = this.props.material; + + return ( + + + + + + + + + + + + + + + + ); + } + + override render() { + const material = this.props.material; + + const debugMode = [ + { label: "None", value: 0 }, + // Geometry + { label: "Normalized position", value: 1 }, + { label: "Normals", value: 2 }, + { label: "Tangents", value: 3 }, + { label: "Bitangents", value: 4 }, + { label: "Bump Normals", value: 5 }, + { label: "UV1", value: 6 }, + { label: "UV2", value: 7 }, + { label: "ClearCoat Normals", value: 8 }, + { label: "ClearCoat Tangents", value: 9 }, + { label: "ClearCoat Bitangents", value: 10 }, + { label: "Anisotropic Normals", value: 11 }, + { label: "Anisotropic Tangents", value: 12 }, + { label: "Anisotropic Bitangents", value: 13 }, + // Maps + { label: "Albedo Map", value: 20 }, + { label: "Ambient Map", value: 21 }, + { label: "Opacity Map", value: 22 }, + { label: "Emissive Map", value: 23 }, + { label: "Light Map", value: 24 }, + { label: "Metallic Map", value: 25 }, + { label: "Reflectivity Map", value: 26 }, + { label: "ClearCoat Map", value: 27 }, + { label: "ClearCoat Tint Map", value: 28 }, + { label: "Sheen Map", value: 29 }, + { label: "Anisotropic Map", value: 30 }, + { label: "Thickness Map", value: 31 }, + { label: "Bump Map", value: 32 }, + // Env + { label: "Env Refraction", value: 40 }, + { label: "Env Reflection", value: 41 }, + { label: "Env Clear Coat", value: 42 }, + // Lighting + { label: "Direct Diffuse", value: 50 }, + { label: "Direct Specular", value: 51 }, + { label: "Direct Clear Coat", value: 52 }, + { label: "Direct Sheen", value: 53 }, + { label: "Env Irradiance", value: 54 }, + // Lighting Params + { label: "Surface Albedo", value: 60 }, + { label: "Reflectance 0", value: 61 }, + { label: "Metallic", value: 62 }, + { label: "Metallic F0", value: 71 }, + { label: "Roughness", value: 63 }, + { label: "AlphaG", value: 64 }, + { label: "NdotV", value: 65 }, + { label: "ClearCoat Color", value: 66 }, + { label: "ClearCoat Roughness", value: 67 }, + { label: "ClearCoat NdotV", value: 68 }, + { label: "Transmittance", value: 69 }, + { label: "Refraction Transmittance", value: 70 }, + { label: "Glossiness", value: 72 }, + { label: "Base Color", value: 73 }, + { label: "Specular Color", value: 74 }, + { label: "Emissive Color", value: 75 }, + // Misc + { label: "SEO", value: 80 }, + { label: "EHO", value: 81 }, + { label: "Energy Factor", value: 82 }, + { label: "Specular Reflectance", value: 83 }, + { label: "Clear Coat Reflectance", value: 84 }, + { label: "Sheen Reflectance", value: 85 }, + { label: "Luminance Over Alpha", value: 86 }, + { label: "Alpha", value: 87 }, + { label: "Albedo Alpha", value: 88 }, + { label: "Ambient occlusion color", value: 89 }, + ]; + + const realTimeFilteringQualityOptions = [ + { label: "Low", value: Constants.TEXTURE_FILTERING_QUALITY_LOW }, + { label: "Medium", value: Constants.TEXTURE_FILTERING_QUALITY_MEDIUM }, + { label: "High", value: Constants.TEXTURE_FILTERING_QUALITY_HIGH }, + ]; + + return ( + <> + + {this.renderTextures(this._onDebugSelectionChangeObservable)} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} 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 b17bda7ab07..d96009b325e 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 @@ -83,14 +83,16 @@ export class PBRMaterialPropertyGridComponent extends React.Component )} - + {material instanceof PBRMaterial && ( + + )} {material instanceof PBRMaterial && ( )} - {material.reflectionTexture && ( + {material instanceof PBRMaterial && material.reflectionTexture && ( { if (this.parent.useOpenPBR) { (babylonMaterial as OpenPBRMaterial).ambientOcclusionTexture = aoTexture; - (babylonMaterial as OpenPBRMaterial).emissionTexture = emissionTexture; + (babylonMaterial as OpenPBRMaterial).emissionColorTexture = emissionTexture; if (aoTexture) { (babylonMaterial as OpenPBRMaterial).ambientOcclusionTexture.level = aoStrength; } From 61399a02186e4500342e2688a8a5e20ee4c2ec49 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 1 Aug 2025 10:38:25 -0700 Subject: [PATCH 29/45] Refactoring OpenPBR analytic light shaders --- .../IBLShadows/iblShadowsPluginMaterial.ts | 24 +-- .../openpbrConductorReflectance.fx | 19 +-- .../openpbrDielectricReflectance.fx | 8 +- .../ShadersInclude/openpbrDirectLighting.fx | 94 +++++++++++ .../openpbrDirectLightingDiffuse.fx | 25 --- .../openpbrDirectLightingInit.fx | 14 +- .../openpbrDirectLightingSpecular.fx | 41 ----- .../ShadersInclude/openpbrIblFunctions.fx | 8 +- .../dev/core/src/Shaders/openpbr.fragment.fx | 149 ++++++++---------- ...alytic-Lights-Specular-IOR-vs-Coat-IOR.png | Bin 0 -> 57605 bytes ...tic-Lights-Specular-IOR-vs-Coat-Weight.png | Bin 0 -> 57415 bytes ...s-Specular-Roughness-vs-Coat-Roughness.png | Bin 0 -> 60687 bytes ...ic-Lights-Specular-Weight-vs-Metalness.png | Bin 0 -> 47505 bytes .../OpenPBR-IBL-Metalness-vs-Coat-IOR.png | Bin 0 -> 127214 bytes .../OpenPBR-IBL-Specular-IOR-vs-Coat-IOR.png | Bin 142421 -> 121730 bytes ...penPBR-IBL-Specular-IOR-vs-Coat-Weight.png | Bin 115904 -> 111329 bytes ...L-Specular-Roughness-vs-Coat-Roughness.png | Bin 0 -> 100740 bytes .../tests/test/visualization/config.json | 30 +++- 18 files changed, 228 insertions(+), 184 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-Weight.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-Roughness-vs-Coat-Roughness.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-Weight-vs-Metalness.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Metalness-vs-Coat-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-Roughness-vs-Coat-Roughness.png diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts index 6b205efc2bd..90c6a465a87 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsPluginMaterial.ts @@ -163,22 +163,22 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { `; } else if (this._material instanceof OpenPBRMaterial) { // eslint-disable-next-line @typescript-eslint/naming-convention - frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = ` + frag["CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION"] = ` #ifdef RENDER_WITH_IBL_SHADOWS #ifndef UNLIT #ifdef REFLECTION #ifdef COLORED_IBL_SHADOWS var shadowValue: vec3f = computeIndirectShadow(); - slab_diffuse *= shadowValue; - slab_glossy *= mix(vec3f(1.0), shadowValue, specularAlphaG); + slab_diffuse_ibl *= shadowValue; + slab_glossy_ibl *= mix(vec3f(1.0), shadowValue, specularAlphaG); #else var shadowValue: vec2f = computeIndirectShadow(); - slab_diffuse *= vec3f(shadowValue.x); - slab_glossy *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG)); + slab_diffuse_ibl *= vec3f(shadowValue.x); + slab_glossy_ibl *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG)); #endif #endif #else - slab_diffuse *= computeIndirectShadow().x; + slab_diffuse_ibl *= computeIndirectShadow().x; #endif #endif `; @@ -241,22 +241,22 @@ export class IBLShadowsPluginMaterial extends MaterialPluginBase { `; } else if (this._material instanceof OpenPBRMaterial) { // eslint-disable-next-line @typescript-eslint/naming-convention - frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = ` + frag["CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION"] = ` #ifdef RENDER_WITH_IBL_SHADOWS #ifndef UNLIT #ifdef REFLECTION #ifdef COLORED_IBL_SHADOWS vec3 shadowValue = computeIndirectShadow(); - slab_diffuse.rgb *= shadowValue.rgb; - slab_glossy *= mix(vec3(1.0), shadowValue.rgb, specularAlphaG); + slab_diffuse_ibl.rgb *= shadowValue.rgb; + slab_glossy_ibl *= mix(vec3(1.0), shadowValue.rgb, specularAlphaG); #else vec2 shadowValue = computeIndirectShadow(); - slab_diffuse *= shadowValue.x; - slab_glossy *= mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG); + slab_diffuse_ibl *= shadowValue.x; + slab_glossy_ibl *= mix(pow(shadowValue.y, 4.0), shadowValue.x, specularAlphaG); #endif #endif #else - slab_diffuse *= computeIndirectShadow().x; + slab_diffuse_ibl *= computeIndirectShadow().x; #endif #endif `; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx index 62c15e411e2..f823813c45b 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrConductorReflectance.fx @@ -1,20 +1,17 @@ -struct conductorReflectanceOutParams -{ - vec3 F0; - vec3 F90; -}; #define pbr_inline -conductorReflectanceOutParams conductorReflectance(in vec3 baseColor, in vec3 specularColor, in float specularWeight) +ReflectanceParams conductorReflectance(in vec3 baseColor, in vec3 specularColor, in float specularWeight) { - conductorReflectanceOutParams outParams; + ReflectanceParams outParams; #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) - outParams.F0 = baseColor * specularWeight; - outParams.F90 = specularColor * specularWeight; + outParams.coloredF0 = baseColor * specularWeight; + outParams.coloredF90 = specularColor * specularWeight; #else - outParams.F0 = baseColor; - outParams.F90 = vec3(1.0); + outParams.coloredF0 = baseColor; + outParams.coloredF90 = vec3(1.0); #endif + outParams.F0 = 1.0; + outParams.F90 = 1.0; return outParams; } \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx index f0afbc61f5b..f37eb493bf0 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDielectricReflectance.fx @@ -1,4 +1,4 @@ -struct dielectricReflectanceOutParams +struct ReflectanceParams { float F0; float F90; @@ -7,11 +7,11 @@ struct dielectricReflectanceOutParams }; #define pbr_inline -dielectricReflectanceOutParams dielectricReflectance( +ReflectanceParams dielectricReflectance( in float insideIOR, in float outsideIOR, in vec3 specularColor, in float specularWeight ) { - dielectricReflectanceOutParams outParams; + ReflectanceParams outParams; float dielectricF0 = pow((insideIOR - outsideIOR) / (insideIOR + outsideIOR), 2.0); @@ -30,7 +30,7 @@ dielectricReflectanceOutParams dielectricReflectance( // 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 * (insideIOR - 1.0), 0.0, 1.0); + float f90Scale = clamp(2.0 * abs(insideIOR - outsideIOR), 0.0, 1.0); outParams.F90 = f90Scale * specularWeight; // Compute the coloured F0 reflectance. diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx new file mode 100644 index 00000000000..badfea3b6e4 --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx @@ -0,0 +1,94 @@ +#ifdef LIGHT{X} +{ + vec3 slab_diffuse = vec3(0., 0., 0.); + vec3 slab_subsurface = vec3(0., 0., 0.); + vec3 slab_translucent = vec3(0., 0., 0.); + vec3 slab_glossy = vec3(0., 0., 0.); + float specularFresnel = 0.0; + vec3 slab_metal = vec3(0., 0., 0.); + vec3 slab_coat = vec3(0., 0., 0.); + float coatFresnel = 0.0; + vec3 slab_fuzz = vec3(0., 0., 0.); + + // Diffuse Lobe + #ifdef HEMILIGHT{X} + slab_diffuse = computeHemisphericDiffuseLighting(preInfo{X}, lightColor{X}.rgb, light{X}.vLightGround); + #elif defined(AREALIGHT{X}) + slab_diffuse = computeAreaDiffuseLighting(preInfo{X}, lightColor{X}.rgb); + #else + slab_diffuse = computeDiffuseLighting(preInfo{X}, lightColor{X}.rgb); + #endif + + #ifdef PROJECTEDLIGHTTEXTURE{X} + slab_diffuse *= computeProjectionTextureDiffuseLighting(projectionLightTexture{X}, textureProjectionMatrix{X}, vPositionW); + #endif + + numLights += 1.0; + + // Specular Lobe + #if AREALIGHT{X} + slab_glossy = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, baseConductorReflectance.F0, baseConductorReflectance.F90); + #else + { + #ifdef ANISOTROPIC + slab_glossy = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, + anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, + vec3(baseDielectricReflectance.F0), vec3(baseDielectricReflectance.F90), baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_glossy = computeSpecularLighting(preInfo{X}, normalW, baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, specular_roughness, lightColor{X}.rgb); + #endif + + float NdotH = dot(normalW, preInfo{X}.H); + specularFresnel = fresnelSchlickGGX(NdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); + } + #endif + + // Metal Lobe + #if AREALIGHT{X} + slab_metal = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, baseConductorReflectance.F0, baseConductorReflectance.F90); + #else + { + vec3 coloredFresnel; + // For OpenPBR, we use the F82 specular model for metallic materials and mix with the + // usual Schlick lobe. + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + coloredFresnel = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90, specular_roughness); + #else + coloredFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90); + #endif + + #ifdef ANISOTROPIC + slab_metal = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, specularEnvironmentR0, specularEnvironmentR90, baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_metal = computeSpecularLighting(preInfo{X}, normalW, vec3(baseConductorReflectance.coloredF0), coloredFresnel, specular_roughness, lightColor{X}.rgb); + #endif + } + #endif + + // Coat Lobe + #if AREALIGHT{X} + slab_coat = computeAreaSpecularLighting(preInfoCoat{X}, light{X}.vLightSpecular.rgb, coatReflectance.F0, coatReflectance.F90); + #else + { + #ifdef ANISOTROPIC + slab_coat = computeAnisotropicSpecularLighting(preInfoCoat{X}, viewDirectionW, coatNormalW, + anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, + vec3(coatReflectance.F0), vec3(coatReflectance.F90), baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_coat = computeSpecularLighting(preInfoCoat{X}, coatNormalW, vec3(coatReflectance.F0), vec3(1.0), coat_roughness, lightColor{X}.rgb); + #endif + + float NdotH = dot(coatNormalW, preInfoCoat{X}.H); + coatFresnel = fresnelSchlickGGX(NdotH, coatReflectance.F0, coatReflectance.F90); + } + #endif + + slab_diffuse *= base_color.rgb; + vec3 material_opaque_base = mix(slab_diffuse, slab_subsurface, subsurface_weight); + vec3 material_dielectric_base = mix(material_opaque_base, slab_translucent, transmission_weight); + vec3 material_dielectric_gloss = layer(material_dielectric_base, slab_glossy, specularFresnel, vec3(1.0), specular_color); + vec3 material_base_substrate = mix(material_dielectric_gloss, slab_metal, base_metalness); + vec3 material_coated_base = layer(material_base_substrate, slab_coat, coatFresnel, coat_color, vec3(1.0)); + material_surface_direct += mix(material_coated_base, slab_fuzz, fuzz_weight); +} +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx deleted file mode 100644 index 6d7b7eef180..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingDiffuse.fx +++ /dev/null @@ -1,25 +0,0 @@ -#ifdef LIGHT{X} - vec4 diffuse{X} = light{X}.vLightDiffuse; - - #ifdef HEMILIGHT{X} - info{X}.diffuse = computeHemisphericDiffuseLighting(preInfo{X}, diffuse{X}.rgb, light{X}.vLightGround); - #elif defined(AREALIGHT{X}) - info{X}.diffuse = computeAreaDiffuseLighting(preInfo{X}, diffuse{X}.rgb); - #else - info{X}.diffuse = computeDiffuseLighting(preInfo{X}, diffuse{X}.rgb); - #endif - - #ifdef PROJECTEDLIGHTTEXTURE{X} - info{X}.diffuse *= computeProjectionTextureDiffuseLighting(projectionLightTexture{X}, textureProjectionMatrix{X}, vPositionW); - #endif - - numLights += 1.0; - - #ifndef SHADOWONLY - #ifdef SHADOWCSMDEBUG{X} - baseDiffuseDirectLight += info{X}.diffuse * shadowDebug{X}; - #else - baseDiffuseDirectLight += info{X}.diffuse * shadow{X}; - #endif - #endif -#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx index dd928b04214..5a41d74dc13 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingInit.fx @@ -1,6 +1,8 @@ #ifdef LIGHT{X} preLightingInfo preInfo{X}; - openpbrLightingInfo info{X}; + preLightingInfo preInfoCoat{X}; + // openpbrLightingInfo info{X}; + vec4 lightColor{X} = light{X}.vLightDiffuse; float shadow{X} = 1.; #if defined(SHADOWONLY) || defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}) //No light calculation @@ -11,17 +13,23 @@ // Compute Pre Lighting infos #ifdef SPOTLIGHT{X} preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + preInfoCoat{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW, vPositionW); #elif defined(POINTLIGHT{X}) preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + preInfoCoat{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW, vPositionW); #elif defined(HEMILIGHT{X}) preInfo{X} = computeHemisphericPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + preInfoCoat{X} = computeHemisphericPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW); #elif defined(DIRLIGHT{X}) preInfo{X} = computeDirectionalPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + preInfoCoat{X} = computeDirectionalPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW); #elif defined(AREALIGHT{X}) && defined(AREALIGHTSUPPORTED) preInfo{X} = computeAreaPreLightingInfo(areaLightsLTC1Sampler, areaLightsLTC2Sampler, viewDirectionW, normalW, vPositionW, light{X}.vLightData, light{X}.vLightWidth.xyz, light{X}.vLightHeight.xyz, specular_roughness); + preInfoCoat{X} = computeAreaPreLightingInfo(areaLightsLTC1Sampler, areaLightsLTC2Sampler, viewDirectionW, coatNormalW, vPositionW, light{X}.vLightData, light{X}.vLightWidth.xyz, light{X}.vLightHeight.xyz, coat_roughness); #endif preInfo{X}.NdotV = baseGeoInfo.NdotV; + preInfoCoat{X}.NdotV = coatGeoInfo.NdotV; // Compute Attenuation infos #ifdef SPOTLIGHT{X} @@ -68,12 +76,16 @@ preInfo{X}.attenuation = 1.0; #endif + preInfoCoat{X}.attenuation = preInfo{X}.attenuation; + // Simulates Light radius for diffuse and spec term // clear coat is using a dedicated roughness #if defined(HEMILIGHT{X}) || defined(AREALIGHT{X}) preInfo{X}.roughness = specular_roughness; + preInfoCoat{X}.roughness = coat_roughness; #else preInfo{X}.roughness = adjustRoughnessFromLightProperties(specular_roughness, light{X}.vLightSpecular.a, preInfo{X}.lightDistance); + preInfoCoat{X}.roughness = adjustRoughnessFromLightProperties(coat_roughness, light{X}.vLightSpecular.a, preInfoCoat{X}.lightDistance); #endif preInfo{X}.diffuseRoughness = base_diffuse_roughness; preInfo{X}.surfaceAlbedo = base_color.rgb; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx deleted file mode 100644 index 95b6dea8d1a..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLightingSpecular.fx +++ /dev/null @@ -1,41 +0,0 @@ -#ifdef LIGHT{X} - - // Specular contribution - #ifdef SPECULARTERM - #if AREALIGHT{X} - info{X}.specular = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, specularEnvironmentR0, specularEnvironmentR90); - #else - // For OpenPBR, we use the F82 specular model for metallic materials and mix with the - // usual Schlick lobe. - #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) - { - vec3 metalFresnel = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.F0, baseConductorReflectance.F90, specular_roughness); - vec3 dielectricFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); - coloredFresnel = mix(dielectricFresnel, metalFresnel, base_metalness); - } - #else - coloredFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); - #endif - { - // The diffuse contribution needs to be decreased by the average Fresnel for the hemisphere. - // We can approximate this with NdotH. - float NdotH = dot(normalW, preInfo{X}.H); - vec3 fresnel = fresnelSchlickGGX(NdotH, vec3(baseDielectricReflectance.F0), baseDielectricReflectance.F90); - info{X}.diffuse *= (vec3(1.0) - fresnel); - } - #ifdef ANISOTROPIC - info{X}.specular = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, specularEnvironmentR0, specularEnvironmentR90, baseGeoInfo.AARoughnessFactors.x, diffuse{X}.rgb); - #else - info{X}.specular = computeSpecularLighting(preInfo{X}, normalW, baseDielectricReflectance.F0, coloredFresnel, specular_roughness, diffuse{X}.rgb); - #endif - - #ifndef SHADOWONLY - #ifdef SHADOWCSMDEBUG{X} - baseSpecularDirectLight += info{X}.specular * shadowDebug{X}; - #else - baseSpecularDirectLight += info{X}.specular * shadow{X}; - #endif - #endif - #endif - #endif -#endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx index d27cbe233d8..803d7f1b495 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx @@ -218,7 +218,7 @@ } #define pbr_inline - vec3 conductorIblFresnel(in conductorReflectanceOutParams reflectance, in float NdotV, in float roughness, in vec3 environmentBrdf) + vec3 conductorIblFresnel(in ReflectanceParams reflectance, in float NdotV, in float roughness, in vec3 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, @@ -227,10 +227,10 @@ // 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. - return getF82Specular(NdotV, reflectance.F0, reflectance.F90, roughness); - + return getF82Specular(NdotV, reflectance.coloredF0, reflectance.coloredF90, roughness); + #else - return getReflectanceFromBRDFLookup(reflectance.F0, reflectance.F90, environmentBrdf); + return getReflectanceFromBRDFLookup(reflectance.coloredF0, reflectance.coloredF90, environmentBrdf); #endif } #endif diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index 9396f727733..f5be25469e3 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -70,14 +70,25 @@ precision highp float; struct openpbrLightingInfo { - vec3 diffuse; - #ifdef SPECULARTERM - vec3 specular; - #endif - vec3 coloredFresnel; - float fresnel; + vec3 material_final; + // vec3 specular; + // float fresnel; + // vec3 slab_diffuse = vec3(0., 0., 0.); + // vec3 slab_subsurface = vec3(0., 0., 0.); + // vec3 slab_translucent = vec3(0., 0., 0.); + // vec3 slab_glossy = vec3(0., 0., 0.); + // float specularFresnel = 0.0; + // vec3 slab_metal = vec3(0., 0., 0.); + // vec3 slab_coat = vec3(0., 0., 0.); + // float coatFresnel = 0.0; + // vec3 slab_fuzz = vec3(0., 0., 0.); }; +vec3 layer(vec3 slab_bottom, vec3 slab_top, float fresnel, vec3 bottom_multiplier, vec3 top_multiplier) { + + return mix(slab_bottom * bottom_multiplier, slab_top * top_multiplier, fresnel); +} + // _____________________________ MAIN FUNCTION ____________________________ void main(void) { @@ -99,6 +110,11 @@ void main(void) { // _____________________________ Read Coat Layer properties ______________________ #include + // TEMP + float subsurface_weight = 0.0; + float transmission_weight = 0.0; + float fuzz_weight = 0.0; + #define CUSTOM_FRAGMENT_UPDATE_ALPHA #include @@ -202,14 +218,13 @@ void main(void) { #endif ); } - #endif // _______________________ F0 and F90 Reflectance _______________________________ - + // Coat - dielectricReflectanceOutParams coatReflectance; + ReflectanceParams coatReflectance; coatReflectance = dielectricReflectance( coat_ior // inside IOR , 1.0 // outside IOR is air @@ -218,7 +233,7 @@ void main(void) { ); // Base Dielectric - dielectricReflectanceOutParams baseDielectricReflectance; + ReflectanceParams baseDielectricReflectance; { float effectiveCoatIor = mix(1.0, coat_ior, coat_weight); baseDielectricReflectance = dielectricReflectance( @@ -230,7 +245,7 @@ void main(void) { } // Base Metallic - conductorReflectanceOutParams baseConductorReflectance; + ReflectanceParams baseConductorReflectance; baseConductorReflectance = conductorReflectance(base_color, specular_color, specular_weight); // ______________________________ IBL Fresnel Reflectance ____________________________ @@ -251,42 +266,51 @@ void main(void) { if (coat_weight > 0.0) { coatIblFresnel = getReflectanceFromBRDFLookup(vec3(coatReflectance.F0), vec3(coatReflectance.F90), coatGeoInfo.environmentBrdf).r; // Prevent the light reflected by the coat from being added to the base layer - dielectricIblFresnel -= coatIblFresnel; - dielectricIblColoredFresnel = max(dielectricIblColoredFresnel - vec3(coatIblFresnel), 0.0); - conductorIblFresnel = max(conductorIblFresnel - vec3(coatIblFresnel), 0.0); + // dielectricIblFresnel -= coatIblFresnel; + // dielectricIblColoredFresnel = max(dielectricIblColoredFresnel - vec3(coatIblFresnel), 0.0); + // conductorIblFresnel = max(conductorIblFresnel - vec3(coatIblFresnel), 0.0); } #endif - // _____________________________ Base Layer IBL ______________________________________ - vec3 slab_diffuse = vec3(0., 0., 0.); - vec3 slab_glossy = vec3(0., 0., 0.); + vec3 material_surface_ibl = vec3(0., 0., 0.); + vec3 slab_diffuse_ibl = vec3(0., 0., 0.); + vec3 slab_glossy_ibl = vec3(0., 0., 0.); + vec3 slab_metal_ibl = vec3(0., 0., 0.); + vec3 slab_coat_ibl = vec3(0., 0., 0.); #ifdef REFLECTION - slab_diffuse = baseDiffuseEnvironmentLight * vLightingIntensity.z; - - // Account for energy loss due to specular reflectance - vec3 baseSpecularEnergy = vec3(dielectricIblFresnel + coatIblFresnel); - slab_diffuse *= clamp(vec3(1.0) - baseSpecularEnergy, 0.0, 1.0); - slab_diffuse *= base_color.rgb; - slab_diffuse *= aoOut.ambientOcclusionColor; + slab_diffuse_ibl = baseDiffuseEnvironmentLight * vLightingIntensity.z; + slab_diffuse_ibl *= aoOut.ambientOcclusionColor; // Add the specular environment light - slab_glossy = baseSpecularEnvironmentLight * dielectricIblColoredFresnel * vLightingIntensity.z; - #endif - - // _____________________________ Metal Layer IBL ____________________________ - vec3 slab_metal_IBL = vec3(0., 0., 0.); - #ifdef REFLECTION - slab_metal_IBL = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; - #endif + slab_glossy_ibl = baseSpecularEnvironmentLight * vLightingIntensity.z; + + // _____________________________ Metal Layer IBL ____________________________ + slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; - // _____________________________ Coat Layer IBL ____________________________ - vec3 slab_coated_base = vec3(0., 0., 0.); - #ifdef REFLECTION + // _____________________________ Coat Layer IBL _____________________________ if (coat_weight > 0.0) { - slab_coated_base = coatEnvironmentLight * coatIblFresnel * vLightingIntensity.z; + slab_coat_ibl = coatEnvironmentLight * vLightingIntensity.z; } + + // TEMP + vec3 slab_subsurface_ibl = vec3(0., 0., 0.); + vec3 slab_translucent_base_ibl = vec3(0., 0., 0.); + vec3 slab_fuzz_ibl = vec3(0., 0., 0.); + + slab_diffuse_ibl *= base_color.rgb; + + // _____________________________ IBL Material Layer Composition ______________________________________ + #define CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION + vec3 material_opaque_base_ibl = mix(slab_diffuse_ibl, slab_subsurface_ibl, subsurface_weight); + vec3 material_dielectric_base_ibl = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); + vec3 material_dielectric_gloss_ibl = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3(1.0), specular_color); + vec3 material_base_substrate_ibl = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); + vec3 material_coated_base_ibl = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3(1.0)); + material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); + #endif + // __________________________ Direct Lighting Info ____________________________ vec3 baseDiffuseDirectLight = vec3(0., 0., 0.); #ifdef SPECULARTERM @@ -294,30 +318,13 @@ void main(void) { #endif // Direct Lighting Variables - #if defined(SPECULARTERM) && defined(LIGHT0) - vec3 coloredFresnel; - #endif - float aggShadow = 0.; - float numLights = 0.; - - #include[0..maxSimultaneousLights] - #include[0..maxSimultaneousLights] - #include[0..maxSimultaneousLights] - #include[0..maxSimultaneousLights] - - aggShadow = aggShadow / numLights; - - - // Handle direct lighting - vec3 finalDiffuseDirect = baseDiffuseDirectLight * vLightingIntensity.x; - finalDiffuseDirect *= base_color.rgb; - - - // ___________________ Specular Layer Direct Lighting ___________________________ - vec3 finalSpecularDirect = vec3(0., 0., 0.); - #ifdef SPECULARTERM - baseSpecularDirectLight = max(baseSpecularDirectLight, 0.0) * vLightingIntensity.x * vLightingIntensity.w; - finalSpecularDirect += baseSpecularDirectLight; + vec3 material_surface_direct = vec3(0., 0., 0.); + #if defined(LIGHT0) + float aggShadow = 0.; + float numLights = 0.; + #include[0..maxSimultaneousLights] + #include[0..maxSimultaneousLights] + #endif // _____________________________ Emission ________________________________________ @@ -336,28 +343,8 @@ void main(void) { // _____________________________ Final Color Composition ________________________ #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - // TEMP - vec3 slab_subsurface = vec3(0., 0., 0.); - vec3 slab_translucent_base = vec3(0., 0., 0.); - vec3 slab_fuzz = vec3(0., 0., 0.); - float subsurface_weight = 0.0; - float transmission_weight = 0.0; - float fuzz_weight = 0.0; - vec3 material_glossy_diffuse = slab_diffuse + slab_glossy; - vec3 material_opaque_base = mix(material_glossy_diffuse, slab_subsurface, subsurface_weight); - vec3 material_dielectric_base = mix(material_opaque_base, slab_translucent_base, transmission_weight); - vec3 material_base_substrate = mix(material_dielectric_base, slab_metal_IBL, base_metalness); - vec3 material_coated_base = material_base_substrate + slab_coated_base; - vec3 material_surface = mix(material_coated_base, slab_fuzz, fuzz_weight); - vec4 material_final = vec4(material_surface, alpha); - - vec4 finalColor = vec4( - material_final.rgb + - finalDiffuseDirect + - finalSpecularDirect + - finalEmission - , alpha); + vec4 finalColor = vec4(material_surface_ibl + material_surface_direct, alpha); // _____________________________ EmissiveLight _____________________________________ finalColor.rgb += finalEmission; diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-IOR.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-IOR.png new file mode 100644 index 0000000000000000000000000000000000000000..d072119169934ff7fd536ce971d7cdaa3fc22862 GIT binary patch literal 57605 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 literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-Weight.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Specular-IOR-vs-Coat-Weight.png new file mode 100644 index 0000000000000000000000000000000000000000..baf96643e5b588eab40712c799f0d204e30afc58 GIT binary patch literal 57415 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 S-Cq!ZkD{EaY!%ov`2PS$F?Njr literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Metalness-vs-Coat-IOR.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Metalness-vs-Coat-IOR.png new file mode 100644 index 0000000000000000000000000000000000000000..384af598c0d9cd4ab7a4973fd2a143e2cbc45ee8 GIT binary patch literal 127214 zcmdRWgP0Kh~D=>Eu! ze$?3g4(O_*BnzkU}Y#J z!Q(Z&#IVm0L^qltnpG@W`4y`}R@A?+z&Wz`>PPB7$xdTmzj{43kor=XQQfXbh$5BE zFp15OP$3G;Y-vWn__w`m$zxxNL+ECm_iRC*7zA!*yVrE^B5_@ z8UB0i@95P3k1nNdopCl#9^!7gJ026~!0=~fm|a!fZnpq>v&l|OgBYYl9h z*|$mfjURYeqR>l!IdXRzt@pM6?slwVT7zoq+jUmpb&T(ghhno|i0IOJcY6S7;S0Zu zzhl=6{>xsk+v^VFtoqj!6i}4HekMRNSR#zzli?8%9ny0To~DW==~y9v|Ivlw3Ii(d~*;&Yw; zJYV)$@V0o24qjD;7cdL0pZ)jWZz2QFccLb?fBz7DD4B+0 zzIXs5i%P_lH@wH@jGQt(JI>rTy9~TugCqtL-rKkneb{p5XYcN@IsMR+*ECE)0gXhX zfhZt=k`kZ|1n@8X3ktJ?GY4lgq??>vm)-s~yE!y98`n)vxY-$7x=6v--=J|?e6u}U zr-){iD!PMn0s&+}FtT?r;-n`ZMLdkgNOl8nhjOl3?}nsjw;g<<5966Gz89V`nmF>k zn0ULp7J_vvhvAd>(H0^FKd)yS|$nu(N8l zo!#s}@09Ju$NLS0z(VJ?K_GHj3G#?>7@dQ?1N-~IjtaT4mdl*wiwdcZ9PP(BvB>i# z8B@=pl2qG2i`ez}uTj;C*Uv@8Sg&!EUD5#nBoHXT3s8{Xs8*|z`9+^3Yk zUJE>R4LrX(;~N`YZ22AkwWgZWp$b172u=;5uV7+lh4@rk+dJ5vOt0e1_@5C5Ug>uT zSr&Q*-aaQ?I9b`cUZ{BB)b6FnhX9e?C5d?O-~bCF!5B#LQyi;O!IwHy#&tLPOaW(- zrWeoeE&}U3XU-f4;+g_4&vBIW=Ovxm|BOZvp7(cQvE#lt|3rdsrw4K@e-Q;?h%9W> z(6gJ?wSmj44pq%(o_C9kri+|33X1S+lGL-Me-xyFH+DkKe(PTed>_R=E0sU2>g~8z z@nbf)yMD@yAcr&4!Jogh#8wR6I*|C^c;5ateewH!QkK)*Ley14(@}$Swp$PI&On!w zXmB|}|CtMM?Np358T?c^2yB=5IyPnd-c54?N6c=n%;vMU{m9?mR4_@p9?Q2HT(E0* zbJ61so{Q$;Lsg#2Br=lV*hJf5%Jb*+CVYJC?v6}Pd!(;s?yldOt-eo9>$t%m%@vz^ zoZ9i~tM^H{Y5f_V2>K1M`&?TgrETzurE`-}hcD3pmTYnHci%E`0Hn zF8DxF$LV4xEn&&MeAcwJua4p$wj2Ri-J7;vaWg-S$?^xp-n>^Pr^eX9=yrIn2!22cIr zr*)RG&eN*9FI8q8_k%smJPSA;F65ZI_$Hd|#+!pi8Ojuj0N}=f{!b^QwPd{tnE9b9 zze}UPg(1B?4!T^;PJ24fMeo*XU#z`PNo(7kKH|`5jA0XffK(wt1Y>)<}HW2vn8d-{qtiQ zrjDchm$ttjFu4|hxb`+pfL;vM^9l)Df3~^eqJfkIL5Yw-go4;Y%PHH~%{S*8=d@d+ zT%_q)x8?`0mG2(5zq8^c_4st$2OkPnTBw={)hJ)B3^E~I{>Oi3s=!^J~2t|dr@Ric)Kwm42g;0@3v@v zGVeL{&e*Aa)9gA;-%aJz^TU1oX0ulL&-8C_c(xQDJ&e({7&+HR!h6DppB~G^N?=I1dh$P&X3lNqS8Q}1;szc#`2M->IDEup^kL~u*=Un#8>H+l3DC1Y&?}f{ zx%$eeBmEimD-;rdl9$I(w&NCT_|&*n!Ggbh(y<-*yYuIRFP{C=C|fb0F|^dGN?fDizgT9BO8*0)ji z_c&KoK1;6qcQ=877movyOE~V0ZaZ+bcOG@sd8t*mc-~j1Ye5w}d|N!uk+DmtYpMma zY^USpv2&Yn=>rHv$}1!BV%c=Fe9Zh;=HxtYx}8mb5H3G*zC5sHY&|omYd;O9e)(ON zYBSCjOc+9A4dR30ux(c*vfz&R1bvWU%`>omo?rAAOY`(<`)=kpdz_j35oxx#Pr)L= zCX$+Zr8k5GO~wZo1RLBY5>|huIfw&Y7n^fm1603TXzK_|*56%Jc@3If|EV&)EMppQ zckcLoZN)Kvk(8w&Q8oOH3{-QD!=1;@FvM5F({G|wBn_aY4ACY{|I&LbP97ptA5osK zf_5A^HF5uSDY|qZ*?IUp&5)|_DXzen?-I}HrBv)8_^^HdX0p)pp+n@7l;!s`_Z#FYmE79c>{OzSK_?Ywh0FI02_ zKmnODnY?a~CdStZ%gD~kUG}~$GxI!M^?jVc=+v>Uq~EdhETA@v&wEjIqZ^+RoJ_gR z#hnNs$OCXC!R=kPG0Cyy!30>y93*pdOig~=tyDN=`qas0K(eoZmF%=*TSLm@QlaXu zLx^<2-y0?HP4^zBdsOgXJ%&h=(Zi=ro9hh%a0_NecoVA(ExD0=25bm zQ}s?5rOz5(=0L(b&z~$!3x$~-Q*&thd`O(aR#I7YAL;jEZ6GAF6NI9yD7LL;gz)fW-$kPe= zl2>!i$`!0ds5M;U{?1M9aS}$b?r8h>;q3BFX0{SvGq<9*gdk{D$jI~}g7lFFUrWPT zHl>?gqx@`0nl=fzPP3H^cI1id>ArT}f@?H+s6I(`F))x*M<7P4HiovHyuJ+L@3+YN zc%9jHaQaxgd#p~!8_#}0CiojbyRd(J-Y>i;rj|{>BFMRwWv2bQ&v^N4+|2(s`KL7-=gyP!c2bdzjetef z?WvknSSc>JV3X|e>0l-%oQ!f^|DEi-)+(J=kmkbY?{8ne$%{VLF(*XH|MXOMJ$Y_c zBlhN)eA6PigpURGOzw9h)178=m0_-NYo9O2+EB~5b-u3fL{_Es!mG4qrY>Y}SI;k7 zI4!LB3rXt-Q6BE+f_QF@S3UZjx07;#uHVuBZgS7BaRP6U|H(NdCkhVo+I?wLu(J6t ze&yvvb0`%Zg|TPpxUC>8ZbH_UE$)G$vG{ZTqMFd%i`p zh8G_xIM#5Blw{B-I3R@bQhq(YyQ74I0Q64HFPoE*Np+4^t3TAB*)2}>@@aPn`|XR~ ztL(b@na-;}g`T%l3i@B4FTEYwREl>$Dt4B5!`Q~z528gS#)jBkijC3oGoK65k$6hO zOWBmhDBFkp>LY3dOG%EC2#y)xSd8c1K#bY#Xu{37RN!gJ{e2Za^}k0U8JtX)KQxz4 zIL<1@B1L4VI$%&);jve=svv3Z6&Jf}3btrET-^ZvuhPFu*bt^c?2ooIbnX7m@8MPj z+-yd6dXu65O(*#8tx7U|d-y&RYGXy2epJYHLe=x|8@2Sm0u(po6H-RiL;Bh5F%atS z@af~CdxW^}w;z?$eEwguG!{GsY7Q>X0$5L!!+y}>PNSN>$Gj9 zMS@y!hFyuENr>+|LgKm*@;`uM2ZeyL`-Lgs}Q zr>rb(A97QLD71EmyOx)mh${JO!y=*SNlQ$4xO4N3QvA}%0Sp)Y#5G?lB1jxM41`%+ zR{80G#}tm`#4o#h{yKk#XniD%{E@aEVTWlp5#?+C7ss*RD(3djVd+SYgX!t?N3Jb; zZT==87_&7bl?aI=uwY_qfQ8TUvo``yftGZl{k;ZcG=J)n+`peaSjnr&>+M&jfgHWH zz0LIO*!~_97Cy6hyyx1l!Ag0&MWulA5c`gft?R{|WtSE(;Gc{&*`uU<6V9K$1e5Rk zie<@fWyt8A8ego8%Z>k~J{Kw(Yd>iuT|7&X?&QSM{s2@BjKA&%+J7I5X79JI!>g?k+OC>4AA{&bDz8FT1*}DQ zXTD>$=kyoc$PUAoueuYmy$-zU>W&@LGqdNv2+?3Z-Lip0@YDqVS|`d<(#AcrF?oOLHP}Qgqe|NiS zS$dBo%Wh8gPhe3q%{SyJTYq=wUNY|ih$9F4%T5fq zAm3xTF_>Y`RLKOX$jS7ttEGyj4zBQ$W4j ztl@teRi#UX_?lNnD}3hpLZm6B(0G2RZ7*I_-Xxpb^n@jU)^Qi zewmjRly3h!Jt|2?VihbWqgWZg$z0tj9%G5Y_zzwyv7|j`!1an4A=f64Py^VvqydH{@?S2Af-4!IBgh~v^!X_Q zOby5g&@g)|TuKQH148l6x39P!=iv|7u;d|X7Yv=GPbbSZq;|}*v##7ZI*{EzxpIU; zXkCrOCx?R4zCX^(tC8=cbtpwxMe*WBz|<=XxniOwf*-tirCpAmq}rFDHHi1tBKu?8 zxrUza&ne(u^19++YQDNXIen@z{*sFUM2S?GOs9xbC!@oSdfoQ(ya-`+e`oWJ!(pWe zY!nufNQX=4czmv3%YMVmwU?e>DN+qXrQaNx`hU4lV)U}V550n+`_Q9o-jvII=DFk7 zv~#HuHR1ys@MzfpxvnS$-)*tvn*Z{F_nsGtI-Nh-|9QL?bW3lUPhzUiDIp1{cbH?k zT!`$vj10Wq#jZto26}DuUN}vuaOf16vn#kJKoG2eVSOhAG$OFDp{|c!@Zw#4xH#T7 zUUOhTmiP~#^xRq6{*RwX6guZlY9`nJSBJAcDd3>$d*QrMVp@l{w{4d6_WA>%kel4Ug-Vlu=T&3>|JaD_ods)s|P0x?XkFyv@ameR?=HBPk>C)1dqq zJU?%6cH(f4r^WFqqWBg|$S&TAF$kdMX%D-gat_#z@_mf%|IWFb`k!o`IDb!%F}582 z^jSK8+=x$PFaMmePSfS2CQro}CA6I;&NqJ)#Kpinr0UAt>+%88m3Xo+Oux0BC$~1J z1w<)mz&4%+SxdW^{a=3BBR98K>`*Dm} zPHK0sio0+YYYT|~$YJSUeBtu>TvKuMQGkTBd!unhvFi%1d@VOvnc&G8BvXqm3(j9) z-rM|_EJ^{qO^eaLE(M$6nHXMNUgTUzTuBI^D>(cGTKACt0B>50oGtd>HMq+>7K#=6$O8 zRQ^ewD7K&ugA){xJwPNqnsK}rds(ER-)0-Y8&>-M$u0-hg>qmYt zx5%Q*4(at{`JMhBY_gqsny4nv)cJ(?!JhUsGRT?f(s3};vp~yM2p*0!nclD7zwM%sYW}W`0V1+{+n7iOKsXISUD( zu;Q4;6Z=3XRP!;Ou6H2*blu(M@1=R5!sd~BznzepeD8P+Y19%BjP}1!zX#hJmW@mC zhm_Xf9;sBmo5I|SKQr-9j=I41d46syj(a5Ft3RI^apkHhdb(j(FmxYk`hH`#uvkU{ zzH5(x^}wOlf7eA{yNwX9R+r!p<-QZ(xlNqHN}h~Ul!Px`HFsY9#7TG(lPXCf$%b_2 zpR8eGn(^$kx&9JD*+6!L4f0F*R9<0kY-ns~RZ*c+%P)Z!uEN6?n0UL8Lcqh!9}t?# z{G0zdWlr1LM^UEEtEkqU&NG~*T*-hI6X6AK8#D<}9-(06>N(5K`)4|kzeIEr#qxci~T&0}1weB1yd!(3B`@vYuXJ}!di#q2E%2@Q{k`iNSRaO5 zWGFP9?kGgF2S0mgR@9rct0XTdj_6H?)F;a#)2!!2=*6CX9pa6cWber1q=SEpvUu5o}g_?8nX4K>apza zeRR+b_ulRB-s^jSSkKCs#JE}na#8q1g8#1cMxWelZi7*~b@aac5v;8@`5#6mNFUot znq4;PZUnDiH~xZYF&0vo1fx!L1;5aig?$uwXeS33tJu{;JEJ}HW+qxP^*ro%d(&Yg zh+e}zot0cp<$sXDi&fXF<+%o*jSXW9qy^ zwZ8W6-+59s@gVcoLM**Z_6KLpKzM{i;>waSwmbvnp_8#$l&M}eM}H44ct_Bgx_CEL zak;5ks!sw{2z_a6LZx}-N-d%I0I#tUrVG8MOXFwPpM?5H-G-(msi$Aig1(ZfHte7d zd&2zd!c-Il@*lJ3nLBQ`U^z~#b!Lp~R7|EC1tUtUes{sVPYJJ7wRovNrg|b>Wd$La2E&E8%4>6uz`87jiT(s!EQnf0y@tyQvDojHV;iyd zWtC^@>~*u&4kC-#vTy0%XbZiu_I(R}CY*BU<6;ZBg#6e~kut6Y7`c88mkq#*V^jOx zQs-yX#GsP5?7fJ{XLE<1c{KXiWcz1-K$Ob_Et-u!9`BLF7XnuX)a6}`fLOJ8N`*t~ zlL`{XbVl*EhQPZbY^+Q40r_W@OWsEXkE*NB`w*fcpKC4NmVC7oH?How{5_RLsrOQ6R>eep%U&W|?abNn;XL6};DCGF;;Jfjz0w?lR{jc?!UaT5G^M!eYM3nK%q&i3yY`yMGtzuEdu zF=C0H9>9b|phLJM?^AjL=^_N*N?UCJf=5|j*OEDP^4iFGH)~hAI&gU^^2~9B-QC7e zw-Xa#N*2sNr173R+F!pWqw_wF)jpq{DVSLpskudS%q5=rTy~fIFc_So#L4iMzhTs`K^C6?9l0yPlC*^2Jpw73) zwwe#67AuUH>OyO@B|g%5hKGhJyiqH^Pv=J|Q>;dqWKO)a22KW} zPxtAd>n=9#!N$=`0(l*@ARVNJ7e*|T&xNqE!eODeduzqx;NZaFF16V7#DDtTP1Skj zM%x|!spAL<@5Z<{RTK|9l^CzikGw3v*LIQU{=9nH2p?J>yl_zfAkkKm_Il}T;d;f) z%xkOXc%UK1b;HCdmye!P1+C7APapHrRro_twR1MBkbubKNZ*dRO$qu*mb$GH$!_c3 zMP1gi1-SZ`+W+eXFuk;F{V=2c904b9M| zrQRDQ3vOaILE5~POb1e?77~&UKqJW>A#P!Jm~3Ul5W2{}*{i@w1h4#9x0w7!KRKAl zWCf66!IA}y@pO_hTlDFtd0ZN;+dumGqZN}@OVfkiXDLfIXU&iboh?e8C1K4(mL9De zGOS!h@wd#-$i^kVq2rah)eFA1Z+gt}VI4c{p7ErORN6XT*Mka23m*eqU{{naLBj4C z;Zm)Q^Wwg@|1`di&N|L`^f34;kwXhOA57?*I*tDcZA=eHf?4#0%jZVw3S><=dkeid zdg`?;X(3of@sSmquco#kQ{itfQdW@rT>md~l{lBzDiMtg4Wg%K$#eVkS0Tsa(n#ZH zSFK!vl!SNzWWWp9HA<*qm(wyTvJ(CS4DW8^C z?Y4gwicCWcu_S-D+pKg{b?>UVNm568zeS_$Gey4_5vi1($A+@cy3W)mNWFdA#OQQY z!_;~-w*N1iW^V%$Hbmnv@!;Fnzdy@DV4MyFSHHI?dw$UB<7YmnZ1kMI+vt>NZ*cax z{@HvX2&k&2E+m95_Q@>$m={*>)cYa{M{ibv$aHBR9H(!`CI$SUx7zosGiX04%)Jf_ zT%Qp^{Yy>oyIysEHvIdVe^M(UKLRG_>bsCUNlMKPv&X~(!u-26WZBVwC2rgA`lYYL zPk*UM`36k+>|3!iau|>36t>gt^4w}Tkd~QgO(tyw3FDwf8no-Ag>iiL@ z|E5ylcJB3$2<~_(zc!O6YkttlbqifU;o5iVthc^_xSu#bX^_bF3P$f&x&1+P*F8Ic zU61Z}`w=8$hkV>_^HQ1nnNr1ft)YNOK4(`B=ifn6M%B3#Liy3Fr%JM}^RK#O_x;Z* z77Dc=H^d@8iyrQ2UJrctWu$l+caL3aiN28>iH$#FlWESHi3z-lpUA z&*$?O?i&wdNUw;$NE8~#82zc|->Z4|^OREO)dO6>Z^yVqEtk(JkJvxxfLF53`1D%Q z|9*a-=x|T^Cw_w}-1(%c^$(_hkZd;f&v)um z?Be6x>yt?eW0!-%4cr(IPj!LYQueGN@BHbi)wK7kxkmSF+x{)KA3@Ep6!7DM*d9ZR z$apR&?SIwC^@s~wf=A3bC8GEAUDV{|(@o|d`u+mRtlHO@Z-mjY3MP_Iv~*b~TDH_< z{!l2uJe5z#96cx|wtVysphTqw0lv*{9TKg&lBDYM6|K`(@x{9C*k?QSkb{i+;GiJ- z>T04d+C5eIF8Bx-7EEj|9wm(1CqBm6(=+P1{l_u)yqD?rvPzoZO5mG9>O1 zVYJFIv>0UcVPc$t%RuKY;!(^u5h^W?wWm$-Y1?}Xr}n zC{2FVJPM_Nh5`R=N$yK*=*LM)o8{(KQJ1}(YK(svV`~Fc5o)a$O-tv7`;69MC}ZLp zGe~zhs*j6dIILmvlyyhDZ~gnFuQzo_J+HsyI_ayIQxa#WLL8G}TKq@9*Z{{wKp4UT+ z$JDo58n-?4b~ARrHeXnFm^LoXxeooPkR8V;8T^fj%yzw=x|LQyqY^27UFe4 z&Ld|yRaXrutL9Fda=w^(b)kI)<1m!LRgg`QDM2}x7G&@Y%WH&(sab6N+3-}Ax?Wkn z=`k^D&wc2?Sb_%)Qfx1Q;x&F8o075E#vhMqt~H~Qe+TX*q@X{@371S@b{!lxP5)Zw zqfHI#66@uq(UgUL(@}=Ezn4~kz? zP2zEJln#z$+CTv%S>`!r`AuJ9A@OuS5P*2lYMED`>3WUkcJc0f$dF2M!{fy~!PNo2 z%-{Jl)>J}^eTrV*B}GL+!Dd4$K>qD}U>hhZ$u`s=3cFgV0LG;r+ew$CE}7#J!(DFL z?^k`;C4Ad%{awbVG6=@@N)Gt0enrjWAsH@=Afso>a)N{Q_u&8}%opC|cPON^FU1_b zsoBN}v=gysJ8I4XJ;bx7w}PX9Hd-im1m#Oz5Qwv^wzSBdg!v%{t@EpqQwbg4@tH&% zfQ9CCvA_D9?3h0s!XF+3shjkElYz<@ig- zhYV;3krpkW_HIwej`lqg1ST;m&ux{egEgcfXsQQHtJ1_nI%` zfX}Q;o z2|gyu=v>O#pX-VYHXPejhq#k}b+-gYM>BIyHITSx#~1t%GaBMpmHK;IVPGn|BW~`XEg@g4`A&_av>&VI;!n(qi8}g3Lsd) zAdjW&AaERZ=GYBlDG4$R=N;AcYLaJD1!4;x%cT$DK* zmC7s%1&C^3UR}lY8)pBQKV9q!)5QHsJ!yAz)b{T$#V?2H)u0UE@9$;zn)>3enWd9Y z3Cnk)q!<^q;$kx>z`iUGtUjk4)h*~eceD`}ROBy@VP=TMLe4p%HDN~D$!rH-wiL3l zI0w*Y;Yk))ne*S7C$KwMx7@cph<^uc;t=~eP9A7QrT(TrTyFKozS-|->;I7)$T>7m z&J)k_@GDCL=4MF*@9P(e@|-aWY$X@6Yu}ckS{jEp$CnXc0orCfS@=X+WRGPA@Oy26}{Al`^Jk?iHcqyYYDCN0fTDKqDz<0W0w40zrmxM4PApjVDTu|OqV46RH zkXK9&3JlE|$bp5A_Z5by{-cD#$$M*s(UV@Hd8d+6Z$nHKdM{pj2Zz-D2kd+mOf%j) z$Cv&sQ9|y?^BMg`oq})=sVm*p$D&cJ8h?lT^Sf77FjVo+M41;F?;p3Rl|4VKL?^Kz zQLgMDESgiud1J{-zy9iBA5Bc=X{_2SjPap&7TQ`#`n-AUax|vbx>&4a2av2D4za^a zxyl-0Z4MTk{R@8o{f1@|woAb8a6Pcq?o;*nDXCc;nFZZhm;(o3&I>2&sbkJ?+l7A2 z>HvE-Vd9UEh^6M=8p8x58_zu+iwpqD*i?pc8AGDnj3IYJf4n`(C(kB z@hGoIOKq^(mCp`Krezm|;i~X|#!aTwxkk*15una(QEHt84xv}o4K7$qU$(1C|GS5| z1bk1*8oWrkwJ4JT%)rQ0eBJ^icL3Lkv*JXWuoURY7FAn_t_xP9f#Q{d@pMGPzglX; z7!hm*vTQCK1A8|imzc~MFE--K<>EpqWSq539#QemhQPrzU_mKikn6zY>LT#qecB9r zoSgs<5By&5o}1!P}F_ zV>*JxU*cTpBlTPnfKVolPcI(VS;%ne*7&o6Z3Y9+%QxKDtB9i#52mt@TrJ|)UxdxO zO6CPkPb-lO=DAw{l)EuSxI`_647nk);P1kUXr%U4FKT!&uWzp-@f-+5ffb;-eQQlGgW#Bx0=i=CI-==lw-;o4@p-Wvagp|mhaN4j4BZy zKKpb2^amlnUSmE=|BWGxmaL6quAi7(O0u)iwjTeyL(SIvU6nlK1Byfz0Fuv(W-SdP zH}>c`c#wGTw2Ayrx=~EJpa^ROqYBlZY}a`iDw7F_s~ZG)W6yPO0elh!2!0}py9!7I zoqsJ>6X(^Fmsxqc$y&5#5AN$QGLliqqb;WP3jqY@A!QNdCXeI5JU{|&w#RU@04UVT zt+X8)!h+IjYv&>4-nseSPbbKKPo)YV+7{M~N_qfW)P&Nxbu_0TDQqw}IE4^w8oWE$ z;j!;_mXOGe17ZV!n6*&MFlccR{luv-(Ur*4oBG)b&y5M!tp|ADM5(RFxR($3O=JK5 zu*&B=>hHM51(@&4&>_D{8jkvJ`weZ;$!m#cMjdZ+_S0oqXb~AgM>vx}Y)&u*?J$Ex zTmx-Ny0_)X{QYOR$vD|1=&De<8QhE1`_fxb?bW105cakAbu2p{cwiNU+33;i$(DBH4Z9OM>F(#`Bc1eH;=mQ^H&&XZcn zL*&gNvE8N|7hT8Lf!v7E=*jK$QBC?)-Qf?~-+Oc!e%B7tl9@WKj)tQW=a)7aB3`%_(>E6mUeEZTF|Mvphea)b42y? zh+-}j1)b3eRl#k>% z9%qEN#3u>FNs@WaP}0kyWaI#27_eU4S8<*iH9PoAYl?UJ+lz-1>3!WNaTLi^Z-Hn| z?b^AYUo2kqgiEPEU|+SM-wJ}~g}{>^(4o-)&bar~T41tCw~PEHW-NkLsqpc-pvu%Z z!7`1-@3+gpC^$>KHUQ@LJ$X)u5D&=>8*v)4eYb7#tC^T$&lgPMNnY;)_RLL3VkkwZ zl|Zhg&`nQq7KEU-+CS|N-l-hMcEd$DWz~sVAN(u1v6Pw(2n+yWH;IQQ1-Ddt3Xf=} zQc3fFWAs>IPb$=l6&1c%9c`aHbl)Uw>hy2)s!?G|B`#Z68~(#-%BNt{8u3uq29uc0 zVui$P@oO;^5UL=*Z%+T!e<=weAc|HC*z<;XdNXFJrB@^Qr-wMPy;v9dVVqzAaHAb( z$x{7mTYBuSsG9EcOaQlkDRAd`uKtwsl6S6GWZp;PDq~!*@L$QQ#Uy*HIXpL=kyt?- z?y&93t#Mr?u(E2p)_53^VOTK#0qb9&%4Llhpm|7$R3A=`mLa;~rO(Y{r@?=|&DXt# zV<~*uF2cG6^mQ3*(4tS^l=*c?Mk(Jb39!r33;*g4!Nwd_rXcmtPg=5YjLJ#(^pQf@ z`FLg_^WSIXdLMHjro+rQ>$-?uLwPgsn z6oP-Z4Y){Ky|EfvQNk75(bb6djzyJ=vjXIcwO()zo8SY!b!3b=J{i$%8C>bcnXHfQ zpwLEYdn^`EDFB31vKfD7K3sB!V2~Lm^Kc9F%+$2-+jI+YQtl+J555Zi{2&zqf+|+# z0&cs3NG_Oyg9eyfEhi{~?aLfKGTrjG-y$xb~QWJIfL z9NH6tv2)YGAs57&@$UBC&$ylCwW*?pkGrO=@20Iq6hL5`881Gx$%LDw141WOAn_$6 z_Ep_vdFG$46KAQ)JS}D@#lB8LTu9g^HlGD zUO}=0>}n+mYn|%Rd#@6{U5sEhqS_~YJ=-wzXPC|y-4I-PvQz^h&#)KCem(LMpCnAW z-DSf_q!GI{r^f!q(3y$sl;Q2DIY%b^T7WH^fSrm>n{3J@t#=)<8U_|*W{5g`o!p`Q zrsVkI0!CtA6+Iw}pVQUaUaO&B9*gvvRVdCHJ44qS)qvEw5g>~S9xzJQ&2fnFCl|R7 z-`dYdM)q0uBKa*6H{*ujQuaTY+c`E(*p+joz`#OF*Y%k{DKKpKpdJ-E)&UW+%0ke7 zx~Z3D5UUE}rZ*6RPRrt5+c9}7`lbhKk-f7tY=@UZ1GoD3KW~iU&s~g8TNqTfaT|r^ zahtL~A%M`K_FioGafA(othJdnRGX@wj$tb{PouJ5ZespoHy9V10xf09F&Jge+Ls}i znrFr4(G$WHMiy@mt@6!b<1EZ&16##w#mk-7LWhI!^5 zfBcs-ZGY#!8Ej2_u#v+>sCtW0`X1$0%2=5Zyo6JdML|_g`slT^bcm=}76u-1*bTq; z`L^p1Wqy}^j#QQZ$I*Fx-_au;oww`f>+$PgwgF$uYFzwh=DUjV$s%Z9_5AFf(J3QP zg|gMA?xVPr1KQaUZESqs2so$_S2NbUmuX)ns0c+{JN`Q1!L>@f&TvaBqJBV$)}|zg z1hc-5j}MfMVm32Cu(aEjlGii09tXX#)Bwo#rcaaZkwMJtS%kku{MXd!S?(h#Sj1*9 zSA8_Xo)-=vEDhS8q!p&_c?PAjOH*&PYthKYK>)@tKJ7Zy=mp_Kp6yE4r}S^z0%Xb)wi`wf+8$83buQ_0pa(et3AK}eDmnwV77Z1#IAhrL(W(uR=2;A)TCj5 zj^^o50T8LXLj)R_3TbCtqYg8Dpi?UQLn%r*=#5E5P_jKiRS}?;vy)diQS_&Ro>sUl zU8x}F{RBaN)#+I-1E#qd+gFjn{JbC<(x-LL7ykTG#LlLGi;(|!-`ntY_G^pw7*am3 z%zvYC!*+D${pCO%$=qfbB9ex~{G(HX&I76Z2X}s(b5}wDa=fMpevxUWPn?({j(;iV zpQv%5MJNy}e7M*M67mf`yc0~9vS?}RGaj~XsQKzHwwk@)J~lJ@gTBSSLiqK!^C=KQo!#fQmky`aHNgMipu-{OidQET?yap*!)Kodsuo(i4PPL4RQE+_#>vuiI() z?c-2(s=;x^ensl^P^{irj_PYyFtLv)-2vk=E;&;KVh}j6{u3M`g#x04!a8p3KD(mHycZv4(p#KgfcVJzrDVyl4jMHh{ArTs^J96&5algH%4}T# zQAYEJpXyjI@Lw+0u;oH9skn3a!{Ks}dK^Qjcjq zx%i_-L3-GoC>GCe`W7X7A+QW*Xb&mHCm1EiB(k@kJoQs8h+rX0Z7=O@4ORNziffa? zcfFIge>u^)q(3qGjerndVMwa~gNr<|;b-G(9$9%EHjwNIBkh!=InxReEEyL!F&kvw zdb;5iRS&}5H-F<~!7V3Whoif3zVak;R)~%z0}$GKQ}iIm@Dk2t?dwxWn_lCxt@_bV z=c!@ak2)1@1f{-cFA)m_&V?<|vU8+4-D))qk3n!)R^#4iv_o9Jbsnuj zuTVAN#|OX^x`#N(YDS;E9s7m}Oi1ACXW5yvdQ;+3ekZ9JlZ};XHWLhE>CB_eAT=VP)%EaOxZP}!l-G<+-#yR`p7$v4e zY+hk|^YXR~Gu%6VVG&l!bXac6E>3P(2tFG~3;zC0niG%*?2isfkrA$b;WmBmy`xpA z;{~gE6OJnq&F;i(ROK6E{EtDjTirN4)f+2x99`QZ%*?+4C1c=Xa!diImTM9L+Mw46 zp7OcpQJ&>%(skHdI@vv=T23A+ZCPz*VIx{ffQwMG=$uj!4Jh+_MN)0Q({CovP3n)3Od+OJL(Uy)y1sJr6xHsYCP_IP~b$aJ~~57gy}Mxf&OM zy?PPTWvBMxj~$WEG`|HIpzXcE+87)p|K{Z<2qrYq0Hg!1;6B(^q{?(;>)l0%hS_nw zreY(aOem(D3tNxJz*nq6NI0S|q#BaPT+WNh%g(pbLOTEe?G*25 zH@s=)Q_+;VzD#6vU?hJYw5zPamJJMl!Il0gPN69e!#SL9#fR_DX7#Z~gFk?44E%0V z7NU^xG{gv|^ACYVrj`ogy8A}I$wtkww9%J^#ZK_gLNi=f&T z7u3@ti>}5i2U4>|=YKpZh{n@yd;3>K2FPkbC4;E$F~V9uU3Jz8my6r?ehNQu#m|dY81ML3oxjur3CS|lHPltFc|aG13`pgMVR2HurUkb z0S9<^0NTokQUxTQsYkZH96%oXKLDCQWxrr&mBywEMF3_-L;X33+K{4iD7j6k2q?Nl z2o%plq@XKQ3nHvufQX<{Kubo_1}=R9BQnaxmJtXqw=~PSMYRSbP;ks56zCD>RTR7+ z7_4e)8zGC#hzOm}HXRg{5YYhkm1w{o5R^;+HXsAei$Nd*4C);Kg7az(fG`4R3mgXT z6UO2NOKHJOTrM8qC3RiLyBaarZh;;NLbF+%%?}`G)Uz~>z360OENW#*7{sWG2_}+= zn#E3qU=64U8Pm1Qo}dO5a2|mI+ey}-ccOqIUPBpR8Y?-34B|~5^P69{lBbzjNn^gdS;wb1IAY(OP zXwO6?5H!FdjT6sOPpkz+q?l9^#n2L{*sbO@f;9-BWWjeLp0P6GB@kv_Kmn~mRp>lh z6K9)sUegXnLIgu-42mc~Y>pQNCPGpo5C%o;yqHj@2;e&fgwAPY0TIA~s(`10)4-qPXy2Ko$ z?t38>Kp<5hMFQuf?Zi}e0#F+==~(Ql_#Wkw%Ls&*TiVs4GF4q6s8Xd(D`>f@LY*Wb zps)xMvm$BN>BM5N`$(t^-YXFZA|cocjRE02NfJ_*7^ucB`!M2=K~)q$osWG4602sw zsS*Miu&I(Q>=0rB=Y>pQHRDLnaOXP_A^;U;#+aN6gGZH6y~x~)HPEqC791;hHDnS8 zCSlHvwbpm-#86!Y>#wfSRm(M^b83l1DX_;3gapoMZBRHyIe;M$M2b`xPAn1vGfW7X zl?VWUMFB!yE$&7lQsx-lNM9ou;4N4^uqw!@yc7WdIwt@?mVD=JZB&FPY_<|aAW-i) zlD81~F+(b#%asI*(im{wqXiKgDk@@qE}}K4;t6q5Q*bpzb!Y9j2%A=BmIO`Ml}BJg zJA`Mf0XrXOyg8@hl?<|=C7evKvdA7Lp&68Nz79g*MPZ4&2BsGPv-S>W z`%sjl66U>u7wHr%q4z2ZHF@?VY9#<6DB=i(ms>_4yxg+2e@3mFO~VjtLIWZ~L`|a= zfhblMRi$bFfA-$(*S0M?@A}%M_c6wtbFIDiIj2s!E_Rh2;$S-{wvYmf6eN5}042gf z4ie%m2ni7+Ug3}65rrpEa2%1CSWZBRZDB0=mXyooOS#HbN%X=3P9%h8j;x@03)d*|Dx;x@Z%IT)$jgmfBnO69w55RD#Ba< zWDB~X^&DD?+yJm|A;Rp4cN)UXV3PB+D>VdQ=Gt;?X|`i!G8rALnjGGALd3m5Woz49 z$}+16qNk{gyT-O95~aXYnCOwQVV<@10gpuwO2}B)3<0DQs-nT-$}x*gLJ;G@AXPL1 z68qcI@bmS~0sS7E{{WU|U`vh+-?hC%oGC^6)*m942$PJAOdb8?B*|K2(2lU1PV)X5 zrT|cjWHP%DJ_diIL-5`I!*~DbKl4o)k;FWk7}-6TOiflc5 zq?>Fl-O(e*oIf_2O3%zp0oyn$2?BFf06DU~$h%9JV7vp3#o_)nDS(;1*Spjoxq5XF zzT36j99w(4I0jo&RF!NkdY}cDVq&tkG?D0OCJ;m*$n4ldxdjAFz(jxrJ_B`#Gon@}mxU*>M$mLF5AwM%ZJ&G(1GbJcwcxLr!vCQ-p4CMURL~ zk<5hIe(f6MPC|BEBgEVROiR^>ae$id>AkIICNGim1QiX?b=R@0NCcBFWBcA2pk~mE zv^IE}aFZk>5P>l%bltDH@*w@QUB3Db{wrg@0=f&ph%62Q<`{?T)_1Lp8U&0^6-H8Y zC$X+uPqG-QOV3U!;YZZTIcj{9paMS9Cpv@?4k6TO3gs<;9aQ^^P_*Cr-8BCRs9 zHfF*UByC*RV$UpzU@=^`%s`T=AQ>@Yr>H6l$%tAcnC?`e8e88RnVcs znktxzf@nP>l7ixU7GY+5Ih${MI$qVgS+7?7-LALa{=$)lgjbY`)^Tl76?3(Z99kkD=JNtPTnk>NqmE0=epz(i-@B&* zl0C8(X_2kxmw7Ev9In_}P6jh1aow#DSxsVZ6{bFHapS_2(K3Z*FRkYDvWyM;<4kqm>Db3bBH4OYlT2F@!$@t>s)j{~K*Q*tOw@b~V^}hAvjSu}v>*zgAq_|wRa92|3BH-Oh0nByx zApm%Q_m9(2lx7<7GUE-!1YmKwJNM$^rb7riI*6udZNK3~?Egf^Z4yXf>$`vPyzW<* z98;?ptx+6iEiTn?*|JBfa=j)qS7j}t`aq$1iT4IGnbA=M>f?J^PDcRe%Zu6Pb&L6+ zNUX_H&{`B98#17XE;K--HAc|=;l7(MxoK3B42r-+$5lxcqj@#Y7&x%|Gi#B9+x<0N zMGXMs!8A6ubP=e(!v^0PGE)?nElBL3F+m1JNX0ZOQVvzmYs?jE=jf^hSu0H$ni%r> zU0ga`*Bz)(0Z{ZI2hAX0Z+)7S!4_N=y}J*08Fyl2j+}LhBzU>@@to{wb`JaYu_#m1ROvoVSooYSH3yZM1>v zmLbXJOA)mQT;GZ4xU>Xm%JZ5eA~S+R>8%P?JuHfpn@Qig@2%%XT<=1JkWdpRA|9;t z`=>8B2Cic%%ByYp-L6-8gzt9!TmR0tTY)Kxhaz1#P10LL1R~s6g|jnyP-sR`wk@LP z5M&~mnPxDjJKaFi9Tcjv6xn)?|2!U54d-jP?=~k@71hSj zYj}tslyAndrzf+M*FIbu3FhtXpn9@6j}wYfB}XRs&Qs3L>>R?7V#mq<=Ku7!0le}4 z4?tNAQ=v&#4x63wPZdlMWhPN;D%b@4w9+_a;l=n-a`#$ zI31)%wjRaMb2mGWzq#X4gk-iBJu-T>mTo*uq9B9OBV!jFsgwKNHn+(87F%W?z`T>G zP&E~KoWlqQf zMfA+fn^}rwCgbIU0oq7-0EHRkUCT>k&$Pm28eW%V=5Z3iLp0JL3?Tt#20&F+x5M!W z;D7lazqeNJu@>}j~j{KjwmGXUTA@BO)7``l+dv33@fF?HL56xlkF5ED0P zZBVcw3Li$vVVip(j8~U2)iaZIOA(ljXmpy1$gXzLu>v;kIs{mYxFN;?|4x2Fis1I3 zk4}bU>#_B*pFgly9^N5FA5{T2h;S+baIT`l;wT0)MrLq-CwK^ol2S{Z>$1#mzWL@a zeeTx*{A*wT(d}}FHMV5+p%KN_nPdpI(Z@5iK#TqUIy**VQ}^JJVJnoOQgOq!Wn_+p z%E-fFW^#Y-#rJgk@wB)B9C9QG=!VhMeSnX1uJY!SYQjvOw}{AH*zpd22xdD1cPYr& zUrmauSr(I8q!vbSWITzCbR?K-sdZZB!(sXGN51CMpZqKU^Xus_Ve4zsRVA6k+SyuC zA9zD1m(Cu{$kutB)D`Vvrl2ZGs>obrD26h*wh)0CGFc2FY%TUcDBGVXv)v~}>(xQ{9@M<#<65s9-7R`1v2{kmi>__YK^^3d>WGB zrRV@|sXjDIhiGL7HVHv4v#LsK>BA})G((RZebIbL{lH6y00~^y$cNd_774NxdFd7( z7s~6JwL%pUIX==wA>g4RBq4C6Ij>uf7LXK8GjUTlt@C_1EU&-z_*Z}R^8h~e^Peeo zJD88n9Z866fwrZMDOxg;X5u1a%;_$3feQLQ%Ryv9P)vrOVT^P}IA3y)eqCmb;0`6| z2|yLwmM{Ge@?}C)U_W5C7Q&3=_-jLtIz$j|$mC_qQeZ}cQ@$BWKWRTT4oR`N%UZGsVY1F zM{$^RbdlqMn+Kp2DT=XfqYYs4KuE|u9Sp+W(+x~UW^q~fLYvMh%;9^Zcc^Iv$6cBVhN^{N^D9#kUEZJTF*>+Q9wMe;Q3 z^Gmi3qSDFjETyVIB1jR3_#_T#i7ntom{`|76&*A+H%XxPR7G@*VIIj^b}eX8rl2@X z_qTpi=?Nt6uh{}3Tq;c9qkXD8RYal`sA@8M;QpFq9u|>I2vj-zRgwF>Ffsx>PI9>f zBr(pij)8YCQXi$oMye- zs3szk!L`LyWV|J)B9aj-u9-B~)&igxCArMfdYZ~K4R0CdDm@T^)_8a2=p`<7r)(NH zJ55j=e$d?#9&A0AS)zx!ZY|dbDyPVh$7bt1R6&r)%oyrj6&s2aQLXOZ`#1mYSckv$ zH@^RL$j)?=`)B<)Sye=po|39OA_nt|)JyN{bt)}mX_ z4!B8cS*k{4jPYA=nuMJYP6e5RH6tLlP$Zw9bLgt(0%i(?AQUbyP36TEG{?IUR+xC5I{|en23zl=rYxpkHnw)mVf(y`@Zj44zoyZYZsG4 z!6oFh*fsXc{bh?3aTimGh~grNQnaefRn~wP?SXCW>y^htVP6|2kqUhGMK)a%tj_#V`E{0D#e<3IerABne(Yl~CS zbIYa57U(@yG?VMP@A4!Rx>T(OryKaLqR#smf69 z$+itqD-|pT2oZVNQWVut4nk5?dgk$=18anvd%xUShFdaz+buhnhoS+H_&w|&E<#Op@ zkPg4y-rvXYM{>({giHTZ=!tK0C9_9hJwNCplkG2uY36_ZkM*SO5yTQd7l7*~O) z+-<1Xf#nu)}RZ(p%?=LY|Jxy9&RB(3a(+GP?)4<*`^*e(9Pv?cwkld$QoxQ`CIXzdI8G4ky~hl;PT6T><8a-PiA5lW){~&Rh@cqOtrOWg zilI1{s?RSQ1*Qz){iXNT`xcNKPH=a5a3=WeGJW|{{N=y$Uw_Yk|KBa5nNdqIV(W1z zc5wO4w^B`tOHW2{eCH8)x6z1}C?+B@O{##VL=YmS2!chiI3RNFysYss#1a*_@a9&F zi6~6vvPN~DOd^?%$h>T^%-R~pSSSVu)x|(JECrDaK?z1cuQ4-06LaLlQUYt7wJ=08DNHIJ*Xfc?Ht8OiN z^2wqkLnWElmJp0nt&=S>lWxMKJ8oy`!53Q;M^Vynx%Q0lkjPZ9_S{BjJ9zEUGZ-0L zlp=~fKH5s1ruxxu{FC^BpLn?x8F_bI=c%?HQ}toJ$PN`8D(&JRfJhdXlgpZTddbLa*Yu)WWL4bG^7^q<7gZ79ev6w~#t1)? z5nNlU7|Gsq3uX?$H(a>59^Br(^tq}VTxDGYlk`qk5ujGhj1UtiZu}Ksv@f5 zwR-Wt{Wre%sf^oGRXUD_T-C8ueuA(RY+l-g}QTrN4IdQaDyqJ`@gLd zuGj3DW9l{lBE_l3^R;6{^(x3XpSRv3dZ+p%6 z{OM`hZf{TPxsh_c^qa-kz?j%w);ugW+#b7iVVu(dfF2yQuwf}9D4A6;?hB$jGv(1D zTLNVCoE@_wfb$kT*fT-8O7WeIX_KgH#E4A?n1@Mg5f!*g0~?z>2!O0bNc(=_k&-)6o2mD|MQ>w+%G;p9-qCqnCSDT+v8J7GRf!XAW*9n zm&_p(gOEMwt^*vH2@@O-_Hiy1pr{JI81hTX)T$67g^W7U87w> zKrb>c?q23)nr|Mx@!I46>o@-SyRiSfs^3ws4#M}QzVo}j>lZ)$bMHUSUwXEk*L<}2 zU{l<$nS_^t@*jj3jL($&KxoRqjYj8esEQU8@Y3mu9;u4Ch`ZDxPmUUyclXhPL7Gy@ z$pL}tgQw6)%A{O_?zn78Wb4@pg6B2PEgw)(d3TP(BCW?%r8tO;UHia3rbUd)rNtIx z&PN4sI{N8mBD5~k?UN@z@nb*xJC@>bjPMWX?q+=qAtZ;^wHu5xYKUu<=OpbhNc)af#%0 zjbc(2lMW#(`T&3?Be+cBCUcR~tT&53zwhf7=Qhj?G-MLh#SF~sNh-$+Q%_#oNQlgp zTw4UtGdsDF)n(ga$V7K!j}7!5RG6SDBKqBnmMs}+E&y*H)oGeVZN7c{kq^A@SAX?4 zzkD5j`E&o&%XKRL`s`0%Z1NBr?5=Ca!FM3j4 zS{o@^1F0h+si=q+BBnoc9-gnmV@I~Alb!=4-nxGg-1cxrc{W(_v z03ZNKL_t)P1d5WtkjVj5aNFWI>2VeaTF>Ir$h&Kv7U_{&&(3^$*Ci>+Acg6MOG_P? z(_qhRTP}-CRYo>jW==(bgeDZwvFlMa)mSVq*PfYWRuL=*TP8It^E}&pc=Pqgpa1-C z|Bj`&UJG!y%<~tYo)5*Iz38V|L988zMXKQbnlI^J<89!usG7LKY=CvxgDt2A6M9is z3`(--j{k2hry`GzHl~JC)lS@BW2%y5>)FX?_kHNv$4@#HId2J5D?2pjdbh^D zD(+u=dU27xJA*%?kJzJtUT4zh1w^$n)8Oa2uBA1?_A}WLRb9dj@mXD9#A_=T5=1I+{ zhFWwB0u+_Zq)?G-i)bO_bkOPOk8c-&TP?4>@BJVDN1yuLACSW_pFY1oR{QO@FT-Nz zifhZ8qYoI+v%4OB2!myrv<2P7UEH;}94A%ayvEkE6KhWbwJ6BbY(oW_pn^Skv)Ij| z#ifs>0J!u#Fq3TL2L=FR*JObv%7Y__Tys1mA$sSJrz}&>0#2f zCje7vouWkM<*vt?8k}ydO#0~dU|wvV-}nCa|Hu#i#P42;SM@H`tAp@8tK&_yExzXQ z@}=i3f+pBHY84PFJYRO;i3my=fJ`VTCQ}tf_M|J;;DBydqbQa#B6!%68Ck1FQdNc$ z(iL;TJmKlN-}i)26sMD_Lj;Fq=y7s347jo>k-WLFk^R)RZs2Ja2+wO@4%#DHkFoWu zA+m2<^x^kcC~#P;Ry$2|svT~he8V?=)2Dy07v5>UxZ26}`F&@?6$14?Fq5gs z7955`1R*%hHkM*-!K6N*Zd73^ZkSw_szg5D^4bH&WzjMTfN9d>q;)JsrW>#)B;fIl zi*j9iRStuH>shMgKyM3sgt>@NnD_UMoyW(9#PMLaPZq$Z!|{#xz44pB>)i;zfB0SB z^{JozX;npLHGTe~*Q&*3G|8*W+7bd2m`ehOWyCAd1j|ygbyGQ19X*xfY(uefvy6Ky zuUj8x$zqzM8VFREVzN}3i@bGi&$dv57CoIz6smG_@CwelCxpC=+kNfvBtS+UtBMIT zThBVlAm(FlP{Rx^IA3~hu{<^rSr&WkjZ+UhK6(A?KK#L7{^igA;cqmr>MN*MWSRG@ zzVxN}?s8t)uiKT`uRWld8KzmC#nObXRL#h|y-|^LqcDK%nI>fBVG>tH2EgmJU)Ej= z5_#SRP$mR9j;kVBG+U48iOg7gG0v5O0cT;~dbSRxN=}-JOtM8hd%m8p?dh{Mg>^!C z`8~8IjLaU&A<11F2!H^kN@*8J-@4yM6@1# zjT|w)KrR!CGcyf4_2Y1mQs55B9uYCZIWp%u?n9wMWZs?IfSX==4oI{qTaUGcA!py0 zMVQz7UX*i%f`W8M_GIrsy71uC40TysTrcgi_NULco~g!T1v7dE7{bh*MKW9@8Odd_ zQWeDUXsU>&)1g|Ozv|KPU-VRb?H~X8x9;z6j@~oLTw90`8J9KWArc*=3z=D~RL4At zGTL<H73?>1G6a3fk|F%a1!))vBC49RE_LSD|zl}i;jDCiCyMi9`H zCx>Nt)wP95ZawZUeQhbq*a*C;ZE~69cr+9CbsJDtQA|ac z`PTDoya+zK-vlJH5tp?ulXhlgt}T%<8wJ^VWX8JoBDqX*oJC1D)GFEfa338V2V*H3 znbpx+1bJEe)?-q-p+%YrGkVX=gbW*Q-rYAdnQx86;b8Nu+eWYDc>Cywe&`?l;q5N3 z>R+y2-3Z^yn&wL}pA?yRcGssW21GIwQ<2M>NgnG6?B!vWWzp;@*zZ7Q$evpZR~e+S zAkWvRj=9K~7ZPLdKI*`|`0}%FzU1e&fLJnrl?a4|}Gno%ZDbpYSx{v&m&;7>lxelNFxnESAy|@cc zvwiVto2nvN3_URUurT5t#OSC?azo>Y}2T4yyD z2LutBB!u&{#|&N8Xj}R|WL0@NnxPlh4)a;WXX8_R}B#?7!%d_~LJ$h4&DdOzl5 zrp4d`b^E|zeSY7DzO=aXt=CDXA`l*ncmaj$+FOJQWsiDft*R<)sV?)P^HgsRi`41K z`#z zHhNQY-80}uCg0ZL(LqhnBNI^J0Br}D$!$#)PLoU(#l>8pcyZ}(-?g{zdXIeVB-M7L zCnFSjcj?8^nQiMu$&85fDw*R$F4ZIf2W}pfc`B}?OpibKH9!7)H3MJPU;a=3lb`wc z#~$BIt?{tvi~Bybe_wjumRS#zT()#aom4=Wn4ngPc+jBh9!ji&YLZ}UIoBP#Y&Mo6 zPqP$5CVO&(E2$!Z1lMZ_I88EF6xUL;RC{)}-LLV_pSITXjT@aE$S?(aSK+h!J~T4X zLUo{5(#ptHWie$C3I%U&+^wE&=A?i0BVYY%zxL05pQZT7*S-FQFMR2^xSQSF`18A# zNdcandvSSm^!qj3Wu8?9o#Pj$$&40i>bgrwnH=n)NbXAknhMCR=j5nGkZj3;E>cB^ zB(Sc5$XaEdrMQ%$b@CVYt@Zr;m)7f=uix0Qii0Xd#E21Id(_$3bDXl0VZPI@U3I&5 z7}VsrxcmI%jmKfjH~*<`{ykgeqkiR=Kkwz-S{|38qOZR`J$-gnMFwA-`&4zVx&=$o z`!#Nk<-EpWR*3XuTVtwf@{%UV)^p6xm&x`xGZg}@r+`Z}A-A9x9l*I%Nn+cw_jHqa z(y3@II#qvhZawo0&$egx{k5at9_-+7#i7XaYhQa_)_!v{3Awd|K$xPt0M$+VHR$ka zhsD&F+t(h~M{j=W6aVC2X)AeE|7!K>AbgMO^*74ewl|Jd6qjqCmeRL=yI4;ylk}t- z?k{nBW9Mtmlk9r;YmAq78^~it22DBCZUd+lOpwLo`F*br0a}mZgZxBQ_Le}JPz@0D z7EkZC7kAr}lM;M>-(I^BQ5<2rh+q>h{$ukyaeZwrfi&0U;P?0K@xjJ15FkV@Yn*P1=-@2p zrRDh=r+L4~s<2iOp%S%7^*u0tI0CE7^K&l`^wF|oIjM%;f=pMcK~0$P{C@k=v+d@f z5IlR)o}3imaWRl;4CZWfV}R=xcxW%1>+oQX6S!8pf3f|sk3KSpJ4>0TCtvl6pZ)`6 zfluG=rWZAwN?D^nx~Zl5-TijESnD~uf~CrfOB_yRsyexzFKuf)uRKm8r;tT)n60`D zg;Di^O<>O?;EMZe3^rb7s-RXKk5lg%k#6D+Gg0vV(!Tg?9T%pz@7nDmB0L^^;8nMX zM~k*h2qUw#aDyAvMMT;br5MRlbiMSi{=msy-BP^1{-Lk^;eYUBzyDJFh5zU~Kl7QN zSLI=vF5C9x@gky^Ykz$7=XX8G<6>T{B~OR4%ue!rZ4v0iT=cqSB#X*nvg2YAX)41h z7|EVP+KOw-5myONh&rh$_SmVG#ZZfQ5ffQkf9v_0pcnnZ)9pA(bvZ1B%w@96wLe<) zymogb(0Z6WL>HSzPjeju?7rojZ!D)}nX0DLul?xP{`#-|*8hv$<5m4()vJT>J+AwE zMc#{{svQsZ;;z-It>t+O6D*Sw9I}XI(bh9EduOSt;EQvwMT)`=#W1Lt1M@%PCW^~w zqa{;?Ry4=~(@szg5!qURY>};nJ0?d0t;alz+Xy3N>)n(^S)HYT5rK@%^R+LtZEFOn zCI+ZTYuUH>!21s^vlhEK-k!edBR}%PKlKML#eebN{I@^xLq7<|qh&VByZbiJrMKvb z=lA`|$;@y%*xt<&31)AsRWkYFuHPKAC=@6rojZ!ubcbaRHOE|J03@wQ2gkKIKr@M8 z+X7_IT(|IH$tNSJ##+SI@f*MX`Hno*N@VZp)wdRA_V$Z*d(`4uinz&Oy9CMP zcyg|5+#IavXqL)DPy}oUgR#dB&jlt(LW?va!ORTMTq4+8AoryZk;P#`f;~A;QeAuu z?T~w0Lip^`4P0hj*FII<^ErsAS~2ZCZw_T%Op8s^BFp1%`-|WC@gM)#@4pWJHPa-cC6hh5Zjs5VoQ)!KZ8>PAX4tmeA_k8}foo*%xy;r(-Jzz@ zs47#@saWg0S==XumYXN9Pp^OQXFm3e|1x{VtNO#QR|nyHUw`2*{l!oJ!p|QjQ>4&2a z%v&v54Rh7Uw{y?#Hrssqv)}ROKk>2OX&?OE_3N+w#T7ZE}URcTxQ(3=M@M$KA} z_QuzI>?eQWD|sY->$jeZ-c6=0L!st6S4$BHkBcR7sN#wwTjb@M1Ein=O`77m<#F*L zJ02YHL`L#hca`bL4Z5_Xix%B_t}S0&`u!!U%W1KjgQ;R`*@G$!5-R64Zf|^(+})64@y#k}x8{^Na1nAG}f5;-HeWH`-q&Y8^DCvCA)HiO zW-S_>bU93>#z<QXOA-yDe2rh0Gq=dLC!plBSHv9ywQW6IEtp zU_bNP79^{oR6So>w1|k-A|iW_QgK@AhNIhAG7>oq?3=II*UeJacCpZ(VF_}P#D{8zXX zf90?Kmp}Kj|B%c{Bq>QAmU3PLk?Obxs)Ar9RhWC=2C8r_vP}A==i6zvo(Vxd1Tu6& z1tVHTshE1dUX)~|Dt*vM9$P)Fy{Xvs(1IR0>hv-8K@Z1XhQ`fG427Z z1?M%YV?@SOM~_@1&)2?gF%TrGY%N-FZ5c52P2N1sA!CL4b_A zT-L!M2x{q-Rq}x`7Gn@&D5_GFyS|10Y^qx3G%cu#GlX}r60*Z{rjt!^?F#$jds1j3dU|I(Ra2Crtq!{6>i9568 zzEx0Qg!Zav(pbGTU=ppts)+=e9)k=shQfd|7yyPjH;rckLv6C9XzMDB0+TADB18cM z5FL-QBFDPXYpz}q)u?Rp)q6hhp>KZm+b_ZfEl!*YXv*Bt#&&aHuv2_}B!fydvW@k1B-XV?P(z{fuRf&cs;{;jI+%Zf_CFnfV&<_C*~p+UpjtPn+ycEoKupust;IB8HcNw? zP@5)-rVe3>sC5)kDI8ftjgLg23b`dO>Vq~xyaFL2B9JoRaAcX(5*DLkR#k({f!p`! zQ`=`@ifgaZty3H2%pV#RWu(lK0?a0L&Qwe5<}ys8+6Xp{LXgQ!kl@mN4i%c9J}4uk zIfzl9iJE1Ms#POI?N$|1a%U80F*Q)OjG)S@shj{ng9sv2Q2;bIKujWH2t}cA6hxb# zwU;_do*9W6RV{O#;b`bW2nY9#%f^$j_RuRI{PtsKVG3tYj2v%o)`!N$ENJGK5VkkU zabZ0mF@>n0Dhjng^cote8wm($OeGggkTW)7jd} z{!4Fo-9LWrh4P1=*A(U$i;9Pp!hu0l1k~;I*{HCMLYA=r_$ma^X;6q-*HH!Ps8=4y z3?V3#b!0+fLPSwjBx49wXLU4$=?3x8_IA%R4k6~2Qr~S9X@_j73TO!005E|;WyBN` zCVGgO0>7Tqi_V~N=tB&3K$Xf%3=&nUI!?-vS;!r#h_fh=imNEM z=%XkoSwut3fEt@9Y`|K~7%XekgvQ6hLI{yDjk%2}LWUsDAgZQLr_4x%f|xvq(>ju& zJTqBFxuv|YF~;#Q6JwY;MnN-v?d^9w^w3i;V(GiFwT;NrQQ_9NtFdFRN(gLeHmP%q zfKcQN1ilVcmGV8skk($-w|!#iM45fMF?SyxLm^p-YKr0X;5zG$+vs##mh>StUG#pt(b%u)3U{Y6^GngOv!S{c7 zg3K8aWf);6vs^baDy(tDOg5wGqybQ59FH?L=zZMW_H4)!FlpV$scmlLmebWjRMZHDtI49gNzx6qg++SgM58D9S!zh ze#2`&{g8vU15LE^R4KhNIs4{JQ*~D2B zPHlN-fe>t}*kc5RY10nK*q8-la5S{QU;qFy1Sv8Ljx%e5)_GoBcHOJ~_P_k_Ows2< zh=VBGgUmEuMuoGEon>;gvr`*`WH~QvmJ_k6YTd-bp)yr?oSO!k5KmY_m8IX}# zQ-{gQhX^njnA8_%I&B&sgUEPba*F^GW87(c6e+!IOnjb^iWUYz!5I>OD5?Ssx-khh zqtU>!!OXI;96}rqb2Y{oBO+>6e(Hli`>n6vf7Yh>wcq~j?|<(rP3;ZwXy7u(jgR@j zmQ}EpkQ5M%p)5m0tSave4l=Zio3ntR&Hyo4hoY(k$^Zt5KvAP=*#toxkE{>kLo7@0 zV+^8eLu1+rC^GdvwHlw4K6m6p92gQ&=STsVDFk7}?O8CEirnTI<(7xTOd%Gz%Le(h zsf)~-@ulDY?%5oS5*~ZxnX9iXL}X`D6}c-i0{~?e_a7*tYK%gJjgLv(r?vrvI4;N; zoYXM|0@08$BnnEXhL9k|4uV4EMTtg3*ZA1@m`(#xbZz9)U={@^Lr{RAQ2Ur>6S~w~ z+c5$tQV61=o70fxrac=O8Voa=Apx$g4x1Q_9SyI3%~!tg!_&w1aNe*-gclc@Fi_pe z9fzR9+*-@V5IdSoy|W0a5rhy7YwCc_1mgk+Iru1P0DT>!VoC~706_vJu@>{3QjTSm z7-P&G4jqmhSX2>7je)Bs7C8ez6Vx&|%ef;ZEQ3tyfCy!fNfVvHEMp{KfXo>pux!L= z?u<$p4%}e>E5G)Y=WU+yA`xYn4=Ue8A{q^xHB?q%Wi^WmB7y)RO7zi(NQ{JPOgp(= zRILR>C__{Lz|;s^i4jnp!#rn1K-3tcisl)OEDjwR(wHVkAf{1DRgl_C;m9y$h7>U> zOsjwZWr#ak>gWY8cIlSIv(#f&rS8mZWhZ+-n8fAatQ^^aqRZ+-3lH@@*To14cc z)7m+cXN-Vl71mZAA&CGHscK!d8@FY&28RyEIVq~Kq@c4pD7K}92!I9G3qd9$C$<}13>8|1o2+B>qrFSp+g2s2t+Z&(J&Xo z#u^n-xBrpHHh#=YVq+6;xp9BlG@IMA{cEETLo$W4cMZFjh}oEFCF%X@S=l{L!yag z3?5cjGDA2k{pzY?rVyerj0kldh@tTjp-p?s93ZNXQq?|)<^_prnqV&?BGHG42pd~v zjG<|w0d)i>&FTgSAqnM)PcSVyV7M$i}`q}DA0XvkS(kqiSes4!X>4c)+6 zn`6Fu{kP6h3P9Bqqj58v)u6aC%2ae#`XXmz*bs>TC^(C4MZ8Gr9_K6|Xw`)2EaU}S zOQI^E(nfb;2ofdk?9?H|7@`AB`7fyrO$c#Pd*_%4tl_mY8>A!v03ZNKL_t&$8%s>s z2vlBz2mn-3d=yKFOqMBQCIUt@)`8W1!=i~*mJP4J`3?W+Gv}azC=!Bfmtl|_V~~hehn!{1gb{G33IT)wr%kM4Gzf#jF@q&?xm8hP3=d4^ z+^j53ap1|Pr|05|fFmcut8d&_HTCh6+m~IsHY@8avrQe!DrA|h$|goIOidkjCIJCb zN)!ShLI_gTVKlUPZrVwoUAa-?ql#>9SHVZ`qfspkI;P|V_96PHO^8LtnPWj*Ex5>x zHK@otRj8sc;G_vv5CRyDTUhVuvhdm;^7~$g(d14Ui zT2@zbjXJ9WW15jhWf_bi!??NC5J6eRkXomx#3&)iXvmpm0QEj92!KY_;KheXss_NK zhN!b9ZdY+u$ElaCnJ+RbGD?HsYcHZ2LN}^jz#7ag8Dm^#2D#0gWkxn=kZoZM>m_TW zTI%Z}>C(ofNs-{>O`?73|v(6C#crSGw024v%zS9)ex`|ArqLXP*)yBsZ*^5ym zieVTH3=xJXbrXnGMWTZDQIaVL3_{t&?J8`Qq4YBKvQzp&M%EB9g6Pc0C>o-saRp6O zBq$tfL}Ph8$_yeiAy5=329_Cf zXN+Y9WHxqSjUkYbuU+%tgL@4{FGlPU;YA7`his;ZS~t3~lA)-Gh9Ib59fuGRDV6J{ zS}p($K}7@^twD)0t0Pg{JX%DYCG6(-ID@7Wf5U+tWV|vk&LW^H;P%w#IaigWIjac3 zjK(q=Zt7?W(GVeI28<;(##y-R;BeyW)qSt{>Nn3m2=sg?n__jPnNFLc$co&6027w8 zhKY*80%!S<1FMt#4 zaMhKTnT{OYxbE6ZeB+rYv*c$rGUo$3DA;>Z0Ara6nK1a&K8=;B4l=1DGbUB13Piw+ zA*hOGhL{Nv^2`hin>o%cj|(;i7@=z7U|`EST0;oHh=wq8JSZHI$#XL-GRw#o^UR3? zT3A~hTWBJ$J^u8$WWj{PN9#LYcjdI2KJ(1_t*^dvGHV6{XCn~~x{OnAGiwQn zRCHLF+)<@CsbUb#bCWrPst9OIYSpWj&>12^X38^bEji1D<56yyfC=j+GNboGm}nFL zkPQ~jFxxEW%sC56jseJIhAkXCu+L%R#@BrB!Q%MB9(f&yB{&M`7FF=el)I7h}Y069nbz#@WiW;|eL2`sCEA!H^1wU$%NkO8)kg({<0s49kpjdJ5y3Dqp#=3!7#0RCj58|`*%)M6T^lmT{o~Oq z-td7>|K;ai3Ok%!$NN6|vExS{eD>M(E3P=0XGClaqlO3yB*Lg7f{4x;XDJ_8W^}p9 zELq2FIRL9`0>e0VFv(s>TvmrSF9Q*k34qbx@!-Kh{-b*VM9g6 zsfjjq{_Y}YW7#++LzyF&8Bs+ALl{Mwu{{GKuwf=b04B^c;|x)1IvQoC3{fCNnU$Up zn&XQ3QYL)a<6~50Buz5`bV0Bf#c%T{U5KHPfgBZ3Iz70kKgXjWU~YVQm0W;4Gs<2gZ|XG8kR@ zjR&VMFj3*h#{>8OV0)5XcZGZA=!qC`btPBi@xX3um4jhcWTq(0VBjDK-^37wnXKWmiFFeIa8OuOKu|+z921DBk1}4(k#S@g zjSxFBaK*vZ03Nc-zyHvwm(C6VaQsBL^>weAmPej=;?ywD6|@*+g`?UFS(9fbwK*k5 z43asciZN9b0ggtQF$6?0YE0v}RFext5dqO!Zi0FrMS%zbkQpa4?<_mZAV2^vCFm%I z5D6d~7-Nkgwbqcc#IS#5tR}8p`NnU4>3c7!DfaMVVvh(fb{soVe*BZa@zi5qKm6?G zb=O|vETXm6a?^yoaO1*c84m^y2_#Bki4dzMIzukwA~(*F4`L08LeoT5Wkc4IGn892 zgo{p^;-E1O#iS$XHc3Hp?P6D!_~iU`>jik`Ro?SuwDgwU#K=_Y79E z>#kU7#21&`_RX)KkHpAlo?f3$i@V-%;Hl#q)y%8na6HU2s+%~Q1&xwr21J2*d%Hqa z=ZrP%3^~h)=zT!IqOeuvRlqQ%nSukynV~d9YLHoHXgX^qGoL#nK@hi{s6aa>! zEGx`7&wTXARtWd)9}O}>9^85FFaPC_(otv+7X*8qWnMP8@?Z%Vs-1A_tFPGFt_)#Q zd!KqgYDDJAw4RkQ)WKP1Lr9nvHi}MXjVd%vWF{iWGE0OpN(>UCdLPTm2d`j`kmJkt?+eW~7ngnM8y6r2?&hog(UY4ao3E@5i_EC^O^~t* z;zKd8WfiI>`Z_oQWR9vPvjC8a%*x8AS#(8ViBLp?7Zvqhs@hj&h*3u)%a}&=rI9^S zd0Aa4@<9fO8vNSW&O8{)Yiq+{W=xiiF1huu|N0-!vmNfa_qInK{Nl-D$6aWm64m)VO9oE$PF-K9h416#1J9?Os9=17)yC>nJJB82GQWPZemq72tZ6} zY85aVB8jRZwdl&I$cHXPTbZEpU>sb1VC`fz8H_Ib&i8)YGKsUm&%E>UFF){ut@ZM< zwXtz#btRup%2TJxLB^o5@~TlX#{)-|7a;NqRjLS@`4FPZjLVF3CfPxwrfDQ~9aJI_ zCLcOmBdXCyR4|4j;>su^%c_zai;NL4AKLw+tdt<`$_F3VOAvi|U{4XgY_K!4Z@%;P zvOM<0lP5Ccg6e3LJ3}GL&W^X3rpAC_a*jtCuMVvUOlIEK!B-*G#pi}8O=1v`s6Iph z$ebArY&!CLABRJ043n{W;ap}A)sS}CkiG>C;`hBQDO zL^OmLqGXvF6t*Y~Af!BtqOjy>G#V6x9GM`7aZbb(naS}b`_>Ev%J+ZqYbPIm_yR{U?F5Ty3eSjsYEEi)q_CUuB}5nyF?G+r4ZlObIhas)!dD{J``hgNq&xpvv>zW$A8 z&c7W1;GricANj>!h4S$e+vQ|ZsuyCDSvY)jG92W?j1jc)(nL{F1DG3#P0%2zUv_S& zu$=lusI-L^#K;dpHa1DZ-Z@-hRiv6Q_aqN z`%T4zj~$;)s(qsZ$r{q*$F~oy73`cPnO43IViAZiMyncCT${&hJ%p$uWDQ=7@4L)i`YzFcwloAw<) zdF1XK(%-!w;#?d%)5e2{03>JaKCDu7{vG|4u^*|Y&jgLQz3iri$5H40k8 z){007lA1V+`XVP+UAKTiT?qA7O4FQnG$+Wrr z&{&y$h(RKxf-zAfZ0b-~K8nujAcBTzP+02-71)vzM*-h>6d}uv4@C~lW;|RCAkye{ z*Iv54vpv4*_RsvyKVImiFX5i|+}-{5<6H#m(mRIS8Jjs|O5GI@G)A%3 zlx5@VFe`l>RRuC@@_{vmQor&D7?FGktYDbDkHjH&Hh>W3`wp&>a&8+pIP}>spJgZ2 zmk#&ceehckJ<^m=R{n}Zh-nv{K_Bx zkN?|+UhebacmL(5p8nDwf9-ouX@ub8Wd}#IQi{xwgp*q(peY7fT{fwb1PMZbx(*?T zHLR+s+!7fxYklyDkoT>PL$gKsfq(ewi3`2l7s8$Icuib?=&7S8 zcQ*YXH!GupkgU=5jcJxSYi$gQ2*em-tg2X7fe?v^m`vAoiI7x8QR^nKi=*5Yg$==R z?!d#PmktG>%&zo~K`zn^2E~e{X=wibYqJZzxE}%UxcdgKp8mn( zCn0KGh1HeZIaWbqST!_0s%n}_qzZt_OcE7TW0V+WR(U}g4hC6XIBUj3>wQ>V9aCtU z{F2ZAlZGvm-)J@oivbq%qOWfc(78niZz;6_kX1(7HcBLEU*c`+CahdDD-;aCt>3~%`I3tv0; z4MEN)-hS8hm*(5wdHAW?M_)@*1y#*5cGePN2x*L;Mo}POLwPZDCMz;KEU;{vmEmxh zQB{Y=9r(gOp3A0j=O1r>^ML~W=Jw9Ute))5Vu-|QjgbH`ifWpy3vAgq=UirqGnb8r z*8AEwva&KF^=cij-TZg|=^V69y@0s$c6(^F^2Cwj+q1xk#^BDRj8Rh$djK`oSZkP# zWs_U0K$$^fSpg7e|7x+my~S?urLS*Y=%wu8Tw;$1f0A+gYgb--?fA*(PMq4DFtR`@ znU>T3R(e|_+75HI)!1 zARrNRH3pjUp=db?evriqHZBOg6icOFZ+N(l3Qy>7$ zF9{~g#@TF;kN2(Ia?92K{ty1=3%!DKhBy7(CyqaNqMS^9S;fZ35LBXys>u8^h=_zp zOoqu?o4b5CTsye$f&cH%FX+#{hnECde(pNq~!=BtNRfAF{e{=%;4ta0-_Kf85eqn?z$_R$CJjsmHe1d<`r zpKa1eA_0JuK*>m!*&0)1#dvt|@`Lw(`rlpXHJuGU^gF-vz55^AS>LRuvsgFL2MIx= zXcUm{VAQ`XQiHXY4hcCO4h(137R7LF<%(;s{OX_m+Y7v^J)9%#5#h@o@BX#le*B@M zv&~sk`PhgAk)SFdqN!uZf&~}1dHVvUK{9Cvq?QzkkPMPRlNmR3D+g8{{rt;=2JZOC zKRf!=@!9swmp=L^UNq%Fh%W4)?dq3L1ln=HTp$8cdop0hCNueXaNzR&-}}s;Ua;l; zD0t0#KYHrO$!cd7$|g2Jf}~AfQ=nMWwV}JL&{_o%u(JjwCO|SohB-5~$Ofz9%dflQ z8-MZgpn>b({=Tgfr|QWxRCR2EhM>tBqPr=uZ;jNLy+?EZw}*3qJtBM=<8>eS#L2@O(B<9~hLSNWoF(>p)1acrZW)S(XIC8^;wi@j%ucBfl5Mb9YM zw+0|WqC+I;1R}dZzH)H&$uEEUyf5*^;@Y>qZ|CG@J*i^trF9I53Ur(P;wS*8^WZLP zoOUumLu81oF}cmhgMF7BeDw2weSX*XVsZB`|N5ifdvvO&kB>bfd|Bf4_x*IZt^>m64E&r_DHd#L%<}IEt$-?VYYf`?a43y&G}yK z3*y?hym$M=W-~2A6*>x3kj@3VOo0pRHpYDU0LgEho>O81KtfFZQpYBD*?4f^ic22( z++UrqRsL|i>sLSdgYP^vIkn+i3XBq>1_9Cbak?o^I}t39hBji44iTVFht9CGW{?lo zRxZEpn(yuf5nqPbBf^&%-ty63f9BC+v+XLBi2_w3s4V!eyK6fxOy729J-EwZ+WXpO z)99QIiIEJlBR8<)1LF_hbNwIwtN-==SIM}h5vTAa4{ z)BbO9AkZaY1V{jk*!qo)DO|BSy!6^D9{kULaUK@?0{Gp3`FsEIzkFx=#HnU7i&Y~{ z)DSfa#AJ&8fnagwfisKa{`Jsa33Eo&x!;%(n8*;O@Zq2s>|ed^RX2S7&;Q@^x9mOq z*w`b&mlIy`)}PrvIca7-)FNSt0#yOD<-aq!{gz*we`q%srgyO=gH9k404gyO16ee= z$w%2GS0DWT-~QQ4z2r0E!@u*XZ~oVZr|Z*Z*2E@??@^%aQo~Dv_e{J0X?MRQ-(~xs{POuOJiqQO@7+9ls-9G#^5Ub0P6aMgpmyH9zWaNQ=eI*| z`SY*cnLxYiA*muVM2?d*JaqNt4}bQ&s^pLT{-?h9_urhHTyG|2tXm-nF*!n^M}a6U z1-3eOu}aVrh?tzLce_22%h3v*c9!;gf$d4w+m z-1zp79(m$qxm|}cMz0!FBdYGYN$0Ms?&+C;?MB`fjlt5Vad8M<+Ae#J)|77{prR7Q zSIx7B*I)Ujw;X@;JT=|8=8pHDI((|yu6z|^BO0JnKXWzQZPI<8W{UM8Dz;CSAJD$L z$P(ES5`C;^)xPU)e(ML{^TfBmc^>TW?qB^HFtby^XPUx@o~u= z+Kb@pG6gPg{ktDswOB`o*x&I1cd=lfPH~|yS~^q}i9XCGv#V}>!}?PXy`*-y_t*d1 zGOq2M*lwmxs6{(>Xe(N@+oZG~(_1{WEtbTV0ARs?>3H9+y+;7u>X!}#y};7EBtunH zVhoKxbz0u{RTOQJv^RZ<`&5+Y>+Vqk^^3vwbtAOs?%?yS(-tu;=|h=|F;^MsqZ z9a<-iq-#QA2=%Nybi=E5j$W8~#d~;>*dxM=7w`Vn->T){&Z${53$YOiATjX}o+bnV z790P3heyP@z?mz>#Tz|NTx@u|#1PD7*8GLJTUFYPFX^F6Z@zWw@S`u0DQ^GpFFpL7 zC#LJuX69oflGKkZ;ytZiNi29e{SzV1?Xml0(AJMH6QTAQaSm-GX0S-Gol9gNP(c!JwVi{K7gj0X-*zrdP!UF001BWNklLLCUI6v<249Gh1fbmMKMW00a9db`LBC0YfFCIdHj3twlDTrkmd$yk4-7H z`b_GuJsGH|MwJ+RRjpln{aZfx{wKfl?U%?Dd-yT2M}!wC-tmdwc<9^DOgBqk#_0Qb zG4tK1PgipnAN1I;_fAKDeb--lafuAtZmMMqRZCR-cg~m%CcD!9jZ!{ zx~#5#?Hksge&n2+;)b_>;Kb8MtCStuhz5aOrf8K)YXNQfZ%%{@MVJaC=a0EG#I|0f zy^6XDlEo3LC4=R(te&^DQ^~3l;%qX#@vUz=_Q?0oxhbxE{asr}kJmf1ST)+jmIbAy zCQ)o9Ad)icoZi~63`9t&V*(>FBH@ApyZ>!1Mtv3pLY@24v8%mpufy*0(Y{dDBn>w= zw%+*Od!PR9-q^y65qm^@C?OCXTG*LVCGxvq2t-p1I(t`hx7%8=f!LCmX<7q_LT^hS=g7fP^`^#@Pe^6bV z3FgUF$!RPiF~o9K-uRX~k3V`Yx$w%{-nMz{M6)xCmDeU{X!BxFKmcVyf&KWO>9Jrc z{$NDYK1r`219BorK*G*Jx;QA%+~2V5R|n|l7-2u#sK%lO@4Zhyu*ZcL9rlRu zqQl+4_}@J8-NUoZvSq;ls-V)#WYOh7&YaP9dqo$dxbz~-w>Vth^p`gJCEqD5cDZHD z(@op7k>LF$H@;^3$hpZ5xb6KvfB3PZtSb>-j}ZwwxzkY~ClhsDH5cU9I~ARNJlcIAnCIK}Bgw5PLM*4V8{hKQo`*FghXyIHl&V8btB3w{vPZjlea4AmK0+(LbP7=isFMHK%fBbmin?Lf2 z!;c;*x64q?yM`{Y;36ZY7yIl)A+=g?vE%myAuMy@!VqV0jso@;+V=pSW|CbSAE*TH zUvc{#C!hFn(}-UEt`D7j=6JPJ#;UCpO!*+7Y2QcH#DCb!_~1^~v~)<_Mo-9nMcB?+ zpiUPq;)M&3anE0XyX`Pn%nM(^l5G@JMe4e~_x;vCf9N|;PB&+M7NUmN^?h*XbNY#W&5X z@4D;ALua2ydi#fd{>bBp%k60@lW5(59Scg5#k2^5wmr}~7iiLjM2y&eUC<%6Z_S_M zuB@VkT<*t2&nykK$A!B?hM+1^mDM{x@_|RbarSwnuYB9P*PlCHZ%<;?s1F(?)ktWY z8iR_YjLN)lfwF14A|-lbLu3g}Y9fwk(pyA^*i!pqj|+Pq-iJc6N?Fd)9W?!#T$u5ne=i<((hiIx(qde!+rWX~aB9yH^OvnrY7ZiwuL_}$lP&Z14cKHUe)kBMXTUdze`HzB~=Gkol-9-tfRi-C*nABzU<`3Na z#2{8ra4Mopb*>eS!&>qs-VG#H{SEkrylsu zk7|k=-+tfL@vUa&yOA25Ddvr>c4M6Z7BZR=0}$RXsrKmJQk zKlDVoxf9A-o6z=7OLj;h(v;gdPlsuH!kRe?ViJ6F*++)SvdNhYk3V+qQ;YX-7T6=givsWdl}|qX=&^FA z4z)xt-PYgld*9uNOQ9Qt1;?F%3m1;A=VihEu8&K1H}2lx7tWqDc}igsADJJ1rLO(f zb5Hz8rg-ChA3Ofc$!ezxO;j)Q-f4?IVJ&s_(*1iL&iSL&e`)LQc6{ov6gZr3`=_nz z^f2g|J*8)m1+DKkv4V(PbKC1rJ@uo-O>esU{hPq!;spdpn`YU&pwnsWDXPJZ1a z$&}^M%D!&ZEfEqsCY#g`QF<8a#lsN0l$oUzDxCl3Pm37$&C+T0r8x5ZSkQhZMtSwy z?mY7FkLD^+H{Ln9(ab8TyLv%YRTRYt*!F@+5y8$IyvToP`Oi|13z>7~+;GO66KBjW z8KlRZt=nM!qxbKk1+(@4Sp4=oe`)XSrE(ht00<$z`Th4kdH-G#>4nE05ndd~FQ06b zzDyMYeJ!{+kask-P+fwmI|jtdPzP*ye~Xl6;oCA=49uZ!6-1feYtsmX4r+rW0JSf<6iq5s*;%U$2iHrSkK?l9Nxhsq6$;gGaY=ONm zySMe_{p>VNpo`WfT~EqXa2!Q$fA>3HWbIUNmu#QdZf0KQrfBOGcd_7H4pLtQV}H4c z1(}Hqcl^h#TWlc;mx88q&Od$k@0HTQ>E6-aE4x0{=g!85?ISNXEJXQ%>BhvTcvx%` zWTb5zw$OsmCHl8{|6LrEy4V;I5nE=*?3f&}WlFBm^oni0qwUt8W(#5O_umhNs-{Cu z_tuj06BqfC?L{^3^x8j2AppWo>0hLS^z9$}__L2aQ*Q5svQZzP9V^&75D>N9a}o>o z6G2;=@3})cV=j^qWOl?Eb7nX*CMQa|&=46y13jNXtMK}*xtHYK=`*h8Sn5-|aJzH| zQdPb2&2QRskX~@?5#a^KFaGzx^T_v)&bBLGM+utb;G&7ze7o)CdiH{X*suPgq>FG7 zA>!m3WTZuxv4x;IW1MFf|MjCGiR2bXT0GOu-%V+l|NV&IL)?7!hwplK|H3aHdFn*9 zQ-vn9^L6K4#pkX@SQdgy{D++{l$cWp-EU5EC0MQ~-v}M6I>_^B8 z7ED@@9J4bfOT5U&b+rU3D%Pva=@MN|ix4lgU7zfCnPTaHwY&K_D!}dc{M6Im`{DYS zhWmC-ZTM*|P0*0e1Sw$%rEQ0uI;nQaz;g=_ry7Y)^(Gd~jmbMMOcYoc&Y3e~ilhj+ zJr*z`q+-os0QJtDlo zkik`(Cnil9+ClR&f9G@-TvCEdu2EVf$fON{xn)6SG)%?3OkzQ9U4mqc zvCPJ>F~%_4g}*c@%U!-r+_kMIP1F;4yT&=+6(vMB5ir8E~2A^`Kp&bw#YK+l_JigY$3|#4@;YT^H2Zm@n?_L+p|zL>O+?% z3jG9`u0i&^GGy)%Mk?r}jwhemn^18fu}6d#68HYfuOEK$WVzFXCdSy4gV6ILEj*aJ ze4$I39z7O>qy^cKVYG&=C1zsYofi50B)GsXI^69VI^*Ba*P1O2U{u*U{6cAycYNsQ zP9E8)CUvZX#8wW@n`gp;SG!aWYPpbhv*4WMO!9>qV~ugvSYvGF92;ZUqyS;t76*6j z;7h~H75ckjJCUv*I9v)E_0`nkMNCFWpPba;Dq|J|=hd-Hlkr&em!Q7hMnB3aT+02^E7{_b~sqg&k%`;Rz(|BL#_Y(uy^hilXIt){G{3EG*WZ7JHx!Cq)^L4nw138jD^lVi?J zn-`NA&aD|(J9KtvZQ*R;Y;H})WSO}8DHHR>xs#)3in(#-PnKnIXO>;dncqb7UQd8P zME^f~@7gO{mz9S-W6Zf$RqcJwd+(-c+F&UJIYx>@EJr8=JC1~ej7{Q8Zf*w}n{G_n zwj82-ij-dwOK~C#10tX}fD>6!uq`|J045lN9U$EVx4HG@z4m#}*_W!d<{ab6hcV|` ztM)l0M5536(0i(MPVL&YtJWH8u5o?FGa&fJZ~b@v#s7IvH}k^Qy&-&&>+t&5JbCYC zKGh(RS#)e7x3npDfT42d>Cz@1lvye%X-b-tj6>S*(u0d(7&IkO>FVpQt%_&Q4DYZt zhwaBrD)G0orfq0JXsQHF^7Y^Jji3AUZ;KT?y!MgnM>q9UtU9e%qkxSGZ0d6@3hEjQ z>X{W>;34gi^DqwMe%u}Q!)_dM(v+mr^el(a$4P9g9nbXp9dp=EbCuCE0>o`!tk(b~)Sg2@xLx1Ai-~0SKr|Vmrinl?#jZ%~gm--eU(>MW^2En9~MN>*c3k1`y$Ha%64>@0q z!^LiVu-hFj_WNNNa!Qc20gtgoplzVNue^45@*=YRaeGgY+uhQCrH$CUId77LqVN93 z|37^7{rX*8_lEF=tv~a=7pLo~PUg0XV(p!mbtHm3Wd)ahi4_+b&Ok~j<(!6L8201%;BxmBZ#?|) zhh7?zRtwl+8=ujq`T06q?<_aCgg<R29%lL@1aIj;4!XapK7&Jv5cxa`;JPvu6^KQS}T^#mry!zlHU-|N3 zKbo}$&7eYv!Loz}FcWmH(|#S|{WLfE;X5wEQx(%C=iGwAR>M|J`VD{dn}73{pPe(` zzw*ZQqsQfV^0_iFGGru06KL8>gKL#E3VW?8z958iN@J7*QyNp+r^tf#Kybg`zw*+< zk9_FiOAq$$3MeV0po_v;+C-(s_}+<4`{dtE3>`NCx0U9N73>X`3)5j_a#T`QN%}2+ z>RUhcbI*2;_?WHw;|ELG9*HH9#?% zlBBHTkS-4SYd-SofB9d1`#1mLulw{bfByZ)x23u_-Oqm4{(r7#n8Py=P0uK-y6qDd{)-+u!sX&(eCAuYcs~i`Vn1SnCsL)j@S{svl3mL_1;3N+a3~K>XJ#LrGK4 zdC0?lKfLkk#rJ*k4}HtGe#IBx9o~88YA)5h4bTf}P+!!2tH-s|?>+%H0z2<1Tq8@a z3a`sc&NI6qijRKu+y3!S-({QpVNLm(m?oMhH=;Mrf4kM|gXGcQc{Ad33+n;^wbah*&*^7lk(0SCv(lR3{ zEdZH-$aZtspSLcNA?cuD2-7a*-H>)UkK=B4c{qIS@4fgde;NPQH_4|zHD2F%HK#A4 zsNRWgdn4!F1Zf*a)^}~cN4Vjc+Z2yG8cBOMYzO(OiN5)nFV#fP`}P06^hF=Qm+AV% zfBwBs9^I5E0>#AlrffHGnL9bmZKeIJfVh4Ayx$j?=K5oQ>lgmVzxB`FeCKK|R^6Se zY6s5M^ybmO;_j@4yFuZ0AYfnIs7gBBycU~|r+43e^t34c*vG!(`pHd0iiSyQ;(#Yz z4e$C`h^`hRvob(#IxHJE)*>c4{?1SS=0Ercr+@M5@1ABW=I$*#-oSCrI~6xiWR(@{fMS%#X)%D%Q;I5(o;;J5SVgc-~185tmbay^t4@jH4w>I8$^Iw-`-(YONT5P-1-K&*pe(TLI-jTzf{p6qj zsh|GEIu|#id*H{sUm6pI#vv`Xtk0p`nj&d|bFVY>EdeJg!V&?~Jb(Tz{4alZaF^TD zJe8?U{6gi@zu5({-h+KnuzVjWi^IZxd0M%D-4Nua(Ao^Vxz#$KPM`kGx1Vt<-mfqH zx;KO`W<7rYrc7li0q`&f`?wVdi!5b-M{)>;2U| zKl298jg%}fKO<{3fxyU8jTCdQwN|Uj>-uAa?u04rI_y7Sl#07LtCZ)x=m zB3H@}(llkmElZ7w@tLfrhtvh6iuA8@{stk~quSs)h1i8%|E^cRB z6@kE;PcWb6_a8le`aZm0&tcuCMqj}C?*Ht2Zm&;PY{`pqx!pH!+nT_;;h?P131kz8 zbvHe#9M!xOJ5F_)>s+mxTmP;zl-v5b+&nffZ;=i?f4EHsuH+g$3Dj553%a{mndT>t zuePH2w(tDt@#bWuu35@3CGP8io#k(ziiJ7GjM7W3k6bE(rj-A>2TbehUk>SQ)MXXk1Q*K#R( z_ITMZYlisjc+L#c#!hT6R_ncpAywwJ)Z_K-w|(b-ycNZh$5(ZleUl_u@TsoaK58Mr zS*%@mi~2T*7h4Yw!DiK1$l^X%JDHbib(&ANr`zLnJC)nH9?eeXll$z9(6FOpgey3< zo5tn)H_`c79(D0rwwaveQFIng*{i*53GpIv&gT*=@+nu^hyj#!raYS-K%*qkMPI2hM?HmzjL#AmT2ADwr&qL zioP*!ob@4qE5NcBc--7dJ>DEY`n?}p-ulivPim<>GG1H(QWfV$27}{h+W#0?c=3=K(PNhtxPPLw_ z#X!Z`WP)Zsm-ORjG=XDuH8+5hxAPuE8)%UJ5D zsYSTm5ljmW&?YZ}Whb=Dw0MUL$TM=kl`O{MKATN*y)E^2F1MxJmU1lhSncF?a?Z{| z79s{d85V}SZL;L4Qs9zAzFTHKyK>;Rklbz$E7SCu&)sK7U%(gmAI}BF>X$IJcuqAc(sbh+81s5_xQU z3S|i;*JEB%ge^l_OZmckYyM|CPF^dPNlT0EykqLtxbU2Iw0Q%I1==L9K)^lPuo;Qr zQmvSm<`}R=ggs_jq90#+sJEf^GgH%dEWzgA^}ryTFd{CF)6M32{>1lvBINKr-}gOb zo@us#LY524BxjfAX-jiQ5wBNj35y#L)LGn%`DAt~HdQ-So2t*%XZP7TGiqZ^@7oz< z6b%#GLmF;?ML6FT3xsElgtmUwvgg~F!dj=}Y1tBAc>7T;C3bDg!mlaf#PwQl123$e z0nQlRa8?>LvO0=$cAv~AvtzBdr9F<-j%KHb2+b#kKv)+e8lNMwvyQC}R{Pb54 z&)E&T^3zD)6*Q}JxxKml-O@An>vz8HYlJUgosP3rBk4<(3d*EQAz^!~ulTdoAZ@9u zHX3<_Ziu5XvaAShE`ZFQf?Nw+*rH=Pd-CFpui+85dJJ5~48{G-vmpfAlo|pnNH;6> zc)M!7IoifOs$!%$M1-VtX+*@cKr)uUJV(bY5ur$EJ?U^AkcdxRq_#jfJ6OiLrt>KO zND$g=&@r1Piq+p(_(a&H*U(MdLJ$@Uy+|eMgjVPIx88g&UjB_Y-zzIN1OVYqinuXl zz#-{uOFUH%J2S(pHxNnDHAyNIdfg^-1196WYl19XhTcXDL@r>H4fNygp4slU&91=N zFBTb!v_0YOR_AG2etmnp2?w!!X~U6itE6}Q5}XNv%VV*EU?ma>cS0a8wH=I#C#Tr=1_cMG~taJ)S} zTWj2}FXg(A2%q=**kAtcGBuUw^K^QAQ*NeuJ7Jlt`ji#K!qTz<^2wPc*qWdfroKF! zz37DX$$32t5Hy03Wwybc^z4}yJ}VQ-8Y?WNwIzYM!I8RKt*3sg|M5TfACzg1CQ6^@ z>B)_qCc8ZaSacD^9o2sx`kX05S<_Za1mGTV!18Dbz(Q7TQ=|Q_wp?c2oP>lnBa)vw zo~I1+ovYKN(TYwnTZcdvD=1;$ zD_JAa=bX*w0E4(s<|pUmoSd`!nh6Zg0ODsKxViM(gyf1*T@ad^sOVXHHMVE$)+ioN zfBd6=Iz(~0J+(q9NUN;XOQBVGg#z%WgulHh&L!UhIL9i7veXFOC-bBG$^2+`Tm9Dj z*6e70azD9GEjzjjWEuXkWz6Z1{#@4sSb{-p$E9FXM%`8r!Y3%F>0_T4kBLMb_w>cUD}>I@?gsy zyj^nlkDrPH$+MOUY(C-cuhtS#uaAZM|6PCSW8eQ@|INpbZ!KaVcb-n=rp6q>;Q_1P z5d|Aga4U+f83-FA0`W~S7T-)43OAlYPd{$J@h#=W4H|;lc~p9xZv%1Y2euKy-B4ij zbNpfV3}g|-@wOSleCjP9nK-08SmRqQT_c!Vzz z3$4i3c#TUBNnPUOR$61v1WIq1dDd=OPh6j|r?&fKQ&NqHs<}r`o?HR=*kAgtpZ&RC zrnPK2Psh`{x322Y@dGc%CFXfX`l-k22Z-oeAY3A4(uGPoDPBA7C^l#?$asHJ00Ro7 z0LVZ$zk()Wgp0TcDGP&AKU)PHom+N|gL^o<0E)4?GCe5l*-@vv)$-=Mcahci>r1`v z4dL@%^HkhS$Z~aM#Q;CMyQ+Fo)zS#Rcv|hnyB0;uGJP^-P{7OQeXx*pC+5D2+VvObDb-lvK!+> z?&JfzH?SDRFb_*AY^l$AhaN$|K1_%kZn;gn;RfKtj`Lq(FS>c}g2m~9_g1^HW9KyKoW;}V@emzuwG;r?H#goL0$8=<(Tf=< z2OZUBgXOVBW4iSNC_>RY=T3-Aw$O!6aiqp2+-Y`wbpya^rBwm#$rH1dN^-M$GwG0Wsu+iE=dc<)m5uKoz0~nyXhYFu zW?!=eo2HAXH?Ba=XV}8!6cnWPb`x)}%GsM1m;X%HbL}(ilE9L|YX=tE-)sGg-}ea- z{PfTK5^5FFo;-1LO=1Ns<$9_jvKt3Miir&yfuO7YO*ptdyvxKxuFYz0DxVt1i&0dnc;|kxZ7D&75bY4ye#t8PAh`L(AMz!jq zgj026ISCRP0@0^$mPIJo#^Yxh-6bfrTITt8Q{&vP-@&>!gwK1`x!gQ@e?Tg=p;ts? zH=tDaQrs{m)tqduND5IMl5P`X{kGSx3v_EQHz<;2tFO%GnA0pE6jY(W0V$_B1H)lgPqPjQqLQd7 zcLN|B#V6;su<!tMg?HQa}3*WvEbs$A!J8^DHnxJ9k}pzE-R8l)Dfpn+=5umLgEM zSUosy?td-syz?$Jc`e5$kCSAUVub)iQHu>(O|;ycbjZWyfo_C|5K0~NPH?Qsde614J`?YFP74VU&TV1a4=qnXfI_EN zFEfCE&fY$HH0%$UC#wz>8N}wQS*^OAPJ|AZDk8KBO#meis&UFVlY{z}jdsnbFM~PH zFs~i75>^mSae+Y%ZW_>Hbtl!sLn58)#t5Ha@tiidSc}8^&S+LpdPTmALO^kYS-m%e z&wbq+!sor}TyEZZ?*p$tEY$(c3J6s=4ni1IMN2%U5r{{ejnCD#Za&g&T(q2s~`{JeymYoD_&?O5^2jce!uF1WB*dn7){^ z>XIy7BBZDip>yCYzBzkZaG@<(O(4%+2BkH3Y#u=fyM-OCzy0n9-gtQ~Mu@7=u-}O!Nq~8k;y7|Xxl;&9DGe99VLuN0Q3Dr4_bMr8 zkeYHhOe!Lq5w;ynwC)d*B5Xu3bdZU@5RsoP*}R6k_Aj=|Du;gB8~)LR|H_~Lm0$e~YdJl7^x%VdG#QRLM#dWfO{&{{`4nrUot-Fky8=fBAi zY&S#4sL|s=zc++0VBH(S=e?}VS!nYdk;Z<6F(|2GjuPhTbhtrP+?^+{r>dpo{h(vM ze(#o!Jm|yMF4CB~zKa~s7E*E6$FTg@N@V@NRgtYX?&{JK+}b~O678qW=rX&Gs~+jK zCAON4LgH2r18{wH1Gg+>o#ME1=8#nd4k%ny36@f65EXYZ=ka}$xeSLP@5bZxTqYBh zi--I1l}i<>x=4(jcOY7~TyXCAcOg7&2s;PbQ)?@L^8j(_kw23|L;Qy*yqicWsI7wO z0twO^s|Imc9mLg6Dgc=W8M7e4$fS}7h~hNOZY`v&=2py(vp(F(ZZya3lNrSBFg|$o zL5jIdEh1#hLGR^5KW~6w>v{=Ox3Zouws2zGsoK)4aeGo-O@2|4o#6sqjmQL9&1 zSLJkKowItj8%-cN?sUw;K@Avkj9udCcybqW5z$ht&Nko7@=_W0ySy8(A04eSrTp;K z%W=F=HPOhQFHjnli1zMm3|TIm_b52d-TJ@19alFwg3S|m5`^~G9d|_$-hf1R6LrlH zNXP+ZwEA3B(fwN2y&-(wYr4J3iPy(!)isH^?~<5^2t7L90C%LAHQ!TE^Qlay;)YTI zft#MLPmyfgAI3Ch=`_fZ0({EV?Ep%)cxda^L*N_zwcNK2S_fZxFaYmtRldBL>_naL z_MDxdtKIXIR&r9f!NLI4>E>ogJf3PPE}D$I98kz{kZK@kH9Q0)6-A3Ntdv?R{WMjA zlCmCoeDH95{On@p2u<69d@Y)qYxKSX=u`OX*4Uig!R6;zU#kEhiuG)w-?*F zbK!D}OnR5hrv4gk)EW$}Spye0RI_TQ+v|F|9TShIV#Nh0vt1tY$vltANEMl9SCQG6 zl4^<_Lel1&<8*U!m#K(I8U{Nmc4NA|E&Gez#e)k0+W0q04sP8tu?^o8_EGqBB z3l#Inohs?>%S}P5bQJC?igll$KZ&$KkdXGa8jlJ(+*s{Ptc32@-F0sWpZ7XlUmteq zy(i`lfJM1iCnP1Ql`4=VNyUg-dwpG^B^+~Ym_#?feR4WpO>^Ochr{b1yc~ucOe*{R zfT#P~SD3SdFta<_8`OPmLXWm{-3f~{bGTUx9q?}UL zm2yN@lu!pu;w;|lZu}w;y8BiLz7@q;Wl`d{ShA=~>!xFyE)Gw`114g0^J=H#&2)3M z8}#;Mb#_U~$!Rty)0oX!&4)oDl9L!wstd#=QU(G_sR({nt9<kX zGeq3E+m9<_DVCbpod9{e3pP*OWes>1Ie3>tf4%LENNhXTB*U^*R%{IkxFbHMF>u%G zC-0xGpB(o2`lgo2p#pL`+3t{#1;)AfFlgK_?wG3!-~tsjH;5jm##LAfZ?Anm&BqBB z7sFS66~}QX)$=fn;~=UljCYX+m*)1CDBi@xE^Rxs1gU#FUyVlCcKQzQPc|C{%|Q%{ z*~0EETLT^N7H+!V8^Y(k?hWB{U4P+|-}(1`;(y(b%36crqUjI18IsCrV#*>=u*Ee& z!)XiuaF6obQH=nuujX#^`-`2MYto+4TvdO!hIdWCZ*Lp6NwX#C zv*d()lOkl4F;xR`(0bB|W+j^rF>|Z)&DCy~-hWaX0D;tm0Vvf~bt(jzGDwL5_r8dt zl@QxB1VH90bj)*o>vKiy~J$-`ZK^u^hVYgU4~ z1IX*^vOnaUahfa-VMjzoR9Vdps0HS}0DI#IPLsRI@zy{4>+g;^IiyU?h#^@FJ>olbly}=Y?>XfC|j1 zOQWEm7^+hRbiDt?JPisN^v>#2_h27xfR27N$!UZFqjZSQY&e z?ren6UtfZu2nzrhNYO@Qpj3Cz6G#;RuAn<}5<1OYAac-R4%Jf4DYXKES}_iqR0)B5 z;6MYZ8bkR?HPxO)7MUx>JgGSG?mIQY!IY#JE*_56xW5=6qDie<%DQD60J&_8B|2Q< zM%ldBGU2T^e_L=~+=8|xR2I@cAge^l*gaCFs#43W3Nz1xlCaq&Bc(i5Pg&<;qFRkE zpo@xVjH(BPP=T?P$5o>27zI%!S*kltAP~K}t~WPF67RhESVV_?hKeT1!={BdsA?m8T}{BI=~xz}zuw_Z1t?s_QGKpfoWpol-CtbssX;Qd} zO1WqwV_nHIZZfy2Is<}XP5K`uX zltcwERq*(vR71Uid7}Ur4_UK{s`nz6yZ4mxY7&+W&|m7|4%XK@(*o&@{#!^DPo$Zb z>M3iciY9k3hJyh~6X~iXnUet2QR~TJrddgvQw1r(>6#QqH#nG+0h)YOHtyC3Nk`fx-D^w)R3CJX3aYEGrPEU#xP^gM3 ztT3DJA_gJWpZ^7$W4HWWWPUv4wrEdf}$XK zDxOtpg^Ex$&^rl$pc++4Q3BOEH@U98Gr^LrlmBP^7|>3Ir)PXJW1#vdp)2 z*%+$GSq>Hc$ra4?V7ftSBj-FSfCUsg?XpK5? zYwfr_*?1xI>^UpRC<>&6oMf6U4{DVVDK1fiQ*}1Lu(0Kg>5kboCs!3h!o<(BM`wj5 z2%v&$6u{;xz-c}isYzmEl-VS!B-sXn0PAuiAfowa>6o~lg3~H zEa}oD5Cz#du%epigq1eeAr`?hLj*~|vQ{A@J5N4X`xVa^R2xh$|@eDH0EBa ziPFiO+?`e>=cq{OlKdGDdxO_%niAloYC<)p?A0WxdoYJO0acM=%n5GvmK>D;B?RDM z9K@UgxKUL=s)z^!g{!*Gj5o3xY>B5A^o+F=O^QUgZTMmkp(I7%?xF&E6O6Z(0IRl= zMn<3@baE~(LZ_z$ce**5ouRVbNmaeLe3+8jY@!O#%_T{#o<^;eV^+FH-#Jyo*KwyR zs>NXRz~Q!r@su95* zT7iJo8|kQfR6LvEb@%8Rs?~xn=V9X#9gijXDS~1ozHDwpSjgPRHySGAS zBB+Era%wyy?i7JJlful~dq9msrf<3iNq6R*qaubG{yj9??7K#>%*649;AzcAR{9x!lX;7wRdcU zS0fn4VZYxU>wJ-ODV{P^;tJEuYo$4MgCtcDwK{BrL#4qS{dW5ghJ@UM=eo z{auosm*X*24Z94b?4JTfhh?3}9$m=r1u zSMQ9@LF5PjyB~S|jS=DoBbfG*R1(CEfjK%B-wRZA$T0JhaU6BXXcg(e;zrkkQ({y^ z@}!zmbB6#{kBt#t)Z*C0eZWYZz?U*XFJTB~XHLi(rDP_>TwR6LDcW+xiUl_n?Jge9 z(l|6;??}1K#e{&yr@_tpP-s9PDZL=&^yRzm4dHWNiHDt>t~_Prgi^f}5E!ydmAgSy zQ3?j7o3wj3N)RoP*34VL0USa>YWNW(LAc!xYKLbptREmWqKmB+Y>1oIk5wy07L?>t zAVEvnH7Ey3HZK=m3IVDzE2>%e!e|z}b=-OM?n#PX_mndLiXV1*oNO3n$TCfwi)F!> zbt<&PIMX3TLasUTA&r25hBea2)v8pB+7eVmf$9tBPm*@y)4U35i?I9owbdd;62&$Z zLUyuE(mQ*c)s`hj$AFaT(M&cZ7+K6!dIQ;N2n~`Nid5u{4}1VB6@IZ#x2G~5G$$z& zPLsRJVW-tN1DVtWdIVRVM9jV6^Mf9Ip%@1VF%zn!4clJGO&f5ww?nolzeSlFpP+df zqI8NdHby^(4YU|SjmDmijEp>Fqz*(lW&t9e^K~lwYH%a6*e(Kf3 zaC|)PFH=&Ki8m8{@?p@Na55hQ_T?NC-I$YBx;aQO11QogeY9AJf`u|D9ioDiq?86* zace%o(l;6@0qe-nPL|Y>V*(1M;&F~<9y}4PG8nD&&T743Mw+KI6$m&afneDr3)2z% zXq1==eKFpv<>$TbCH}lu^&;>DTq%$ReKj=Bo=qu$P@s!?1N1~ML^>XAna zAnh_*Lf|eUV#bIOBehy9Q(8#Gn%BQ{j zQ-$vmZf0-B)!o1$AsQh%#C3njcBn8=k$G({S#!XEXNs6Rx z$bD8gS-a^VIXQ+f9`FPdqX?VR;M7s(Lc&#hW`lunHup*>R8)1$3BYS_d|)aSIS+zy zCuMRGJT^=wsfe-#Ylov@!bFcXX|YyVALs+z~V9sRA3ReoA0s~i}!S*gJ5HIqZ<)) zaFX-AT7KT^UgFPtx!YtlNg4*6CL5AMXy%$QxqzZ66s3q@szfVsEn|*|-Y)Nig2NCP zbdpe&A)!JfP z)4h;GW=@!E8)7Ho0$+kcI>{^|Ii-gWABL}etR<_CBX4e)Rcn?~d`MENsYucuu89Ok zc_fWCq|sPLxP$|n{u~`tkQ5dq&ZSvSm)Sj$C~DfbfOXNjP8o!o7|vB z1dMSfAop2M#r6Y=b-%&g964e31`=s=(!*0Q&=o-Ra>RL<+09&XmLapwo>lXJ)5((w zh@_GbBOfHd7^ljVIw%$^myjr9!iS0sgPNln31pQaqZ)F;ajIjMENa%HvSmsaLuIpb z5HK|d2i05!3YycbyGIcd3iBwVU{C>hESL(DuoNd*O@@q8=)MpObV>uaNVRKLr~g1fMOn2Gi<*Iha|hbnBkQ}dVI86NphMU zh=i(ubmMYAYm8-aBPpsW=ah%%rjG7ctosS|&wKreZ~qT5NERPQ?h><7;AVcBZGek% z07qq%4MK<3>TWLLy(|^X`jK4;f0(LB31OCU0>L4(n%C+}mL?h%mR@MIf}p2h_Hep0 zE8@p$y}P_&{90>)(~W*C(cSK#UtUN`RP`Zom$@IP8WRl6X>?PVdxe_-npAW8?|c`2fx(bz^JH1(wRTR_#L6nCSp8Vt=%O4lc2O~0XGB%CR(CUzAiilfy^Y`q>`#(t`EQy3A;IW#v1-w4?@=8Puv*Zt@$qCXFnCVf?sW9 z|BU2Z+}uU@U@wqC^E$P{;W#f@*Zm+al+(k94?-0G>Nots307$odN>CPRk~3U zrs}nNrJD!UfTMkB2k48psl4Er2{7ko%*KH#F_W*o&FMp;CTil)KE#LcVA=pe7tq~L zvpGEpUpmNPKnjvEkLbl0h)`#sVcV8y@*f6V9-_YNV@6y%@5Dl)E^u*I)nOc7ed7Zm zic;#_bCwjUFb$FuY<5X7vKF7K&6S|nVl>+&?s9YNmR^OBe@<+UU2S$z;5m~tz^hqG zo-@roC#pK#a`OGiA;nD>2GXZub2U}&M?Boipq`}(gWg6eHjEf(<_#IQj>er`wJ6UbLP|eSkg*Xv3^V^fLQ7wB;H217b;zOb&H+oWD?1H1k+|A4cZc)q>Nm(CW z9zqU3`a^%aTAg9isk%iu4)E3?@3Z+l+mP9UMW-lt0|$*ZJOW;;oBPtaRjbdlhb+R{ zfu0Ab@UWAVSgM6FsMXDx)W?iPyfHhzRG*9APPJ5zMhGrMnsmB{vO7*@WIDAB2+auz}E>2SHM3#{ zx`^k*-3|&n?2y#wQdPW~O>-r>XQ1wMpv|3_ite;B8lW?xYZU%4vU(lz9>BUg$4kiC0<@6v8RB@Zml^Ie8Fp8D*Yj z7%0*9E26-D5Cw{}I&u~gbMf6EDIpP(MU%|4ry%Sy<}3kp4AL2ZPN*U$g!?|`2DzMT z>z4pfD>Oq8F(_TIAD~G}r8!Dvbssb66oItXE}Bt`zV#nP%JPREhnF*}oAC72)PVPCQwV==mua)CYoy=J^ zrIgo(fv@{l{=lz(>i?3%uFO;3k8`oheVU9Hd%2lOM;h8N!s3#Xm?I~F>zE~pOcjL~ zvY2C<>yR{OQN<_%K`GWC)&wb5nX{7C>WMB%Td$EhcNs}oopYu2QtEMXW+cHNtl}wQ zKT6JeoXj0YMo}=JFvXZ$vVz1oh#M=oQ%PB(@+=AF7zIwIoKj9h&zIb<=eh0;;R{&* z?!WiZ|LMnn^tIvg=GKlyUfIiJelg%!qEk*m*3w64izJaTNmfY;h&Wk^Xk$t$E!L`_ zNR+a2Zv50vCKWn{jOaI?3Pmuc)+R{uFi-_aF(k1DjiE<|CmIzhONs7?R&5IS$uPi- zrFxP`#6?@N7w1&X&1$V8mNUkk=AvKL(vC#wYs2Xqytjq&fQK*@oFyQFhJ-PEX9V5+o_Un zwW@f^7y8Gj^p^XU;8ir+&}uI=ctYD7XYLWfB5TO^f7$d ztzZ0SpOQ2^*pH8|>zMVBWU3rg%sAK9@DQNTU_LQI1hcU?YjkxHNf8Pvn3ob^v z+)1eQF=0?7A;=`G?nzP2-C2yKdc04C`vFNXo2w$VKJGS=XUMqR%k5;5M@yNdTA8iZ zAcb>PTwV^tFbre9c=?ro>Gyo)XFl`UMHGMdkNlgz`m4WsG2};2%9u5p)66-|gusl4 zy#}f$y5J!w#!`8zUY%2A@S%uP0dwX-R5)my8me)w^uR7AL}*-{L&7e}!@Z6gyq(x* z2$7V7qIhcssm`fzt{zM+3J%I$#$=u|k^n%d4MnVqU52?EBA|!6mugnrtEo_vTs|CA z%Hw`~`Hk0q{%1e6y+JM>)F)4lmnpsb{X(PqSmAq5%xs*ipDL?! zYP98mc@j+3he4Af3r1y5B8sU5`Gb$61|YT+A2SBUOMAT>gRK_(j3gYD+TqtKF!N$= z?urhmCJ%!UOj*K#pi_m_sDe^`H%MTt1D$(18jLoZfGNwx!=0wIzc{@16(9WHe)6ZD znP9P^Sv%@YGBQ5-IahItCr&DwoYD$6Hlj=OE zfcHo)uFG zQkFm@(&@Vl(jVV2sau1TSS__yvudiYD#K3lAVLmf9(KDAfAEc;KNp26nPkX>+q+Nd z>o1K{RUW3D5#Kjw>S8!s<8138whnh2iyCH%F3NWY)BPQeIECnJM2YG2P zG2L(~Ab6U2xtD|h;JOK10AZ=o`G;sh0T3$qR5--A41<6w(O-cfgYc`P=Y;67BiyQ4 zH7k}9HDlb%xJw{3>;AC+$)Eh0tsMUMfA~*xrmHxtRJlFz^_K<#e2@7i+CAgz;6_oQ zOQV;D%#}mdn496@Ie`P#X8K*0K`|Rol>|zKioAZIwe{g~uK42B|HIy!{_1jFXMSti zdso#voOABwy}Y~}HMlKHmL*wg$K7$108XdVw&OV64W|lI_-DOO(VxA~jK@c*irnZ&mHR*2;%fhgKxg5+#zC3eEyQ5&EEau}lGDiT8pMwyq-zD}La6g+m?8eYf1?SdY_jzz9n`W5Qw}WJcnqfS*RUwD4u?AlW(80__$jq7| z5xO~Ntkr}l5hO5P&_|FMlE>oQfpD4|0&EL&#%2!SyID`ptz=wx6c5sDZs5X*V5$J< zMId4>f*#Y%=V}g6-6sbjkHn9ro&?te?e+=?=q>`<%$kCFm_0ZlBO#HLyzaZV^R07P zZ&;T%!Ut3T{P%zVbD#g*Q-{Ot)3%>{$cO-jK2`72Lg;!eD(NDda9Q4%yD-kxI|iX( zBre0!*nTiW7T6Xf1VT5pdf|g+^dc~15RPG~1G)(C^385lozQCwC7i2!GY9l)E*K`_ zxOX~}GkG&}a3WJRywG3Nre-><3Efvc^}Tc{GIWwAAa?Fw}1Gtz*9loCO$h?yhtjERc>FFWXez&6D=9LC1X=(LRE|L0D~u7 zSZLLjx%XU+5VByGX;U!dHgmJ)AmnDw=v~GxE#y){Cx*m;j9RT;fE7Xq?C40KZX{r@ z4G+K}T<77YN52p!ySq*MX4SlzWFW%6=j~Akz}`J=Qo>rT1s4=xVJ!iydaf;aZ!pgm#`YA8faS3F#8|5lK^E*1Z8}N>0A8C; z%@d=!3qhB0RZtk48lfXW&WHrAJ_r9Ey#{8~orKJt7}Z@6nmV{MfdeE4HA4hue9f+; zv$ehY?8ra@!%DUXJs__Rk3RO%UwQgV&%V8{p38c@x;zLUOg;UjXG=c`$*p^15em@( zArOEF)M~moxPfS4Lw5z;K_W2#y%Qh;bQgm7U=OepA_#?84iH@!X7#c9ezs}${cKaS zK4Vie_olv^%+wsbsv`rES99bDyYV@EY~&?@x*_^pEwQ^hu>-j;qEkaML=&>}eFN}Z zz?!dDEC~qY=*nQuHy^$Ez3;yIL#?=XXP(>XQ1acA8G{sK3*s_Hf^+kx4j0)P?$G6+ zOUFylQw*a*r$?}u`T>~YKIh=T984MCSKm*zueO_Ptd=D1zGi0oIgE5Zs{;WNwAX;9 zX`k@be?Q1Xo zP%D1>_kQ<_U-;s7NGE5tHH(YB10+U5Fom(2+0u$Y#^e;-0H6hf3BDM&Au%vh;7OU0 z2_ux90NlOHcs~1n(y`iD?R-)K$O7?TOx2otSj7z;5URO?10f4kwcV)WY~98EdsZJh zird~$u&Tws5861Rx2EQf} z$qVB&yV~E9|6(Z~zYz(OU=|1&S8cJ^bR?W+OAJg%7p(vXbL$dT^Ktg`S@*M@k6N3r zI;!gKUe(6t)(jDYg}RI{o1x{o_6b{VT)#1fhlfuPq}ts1K3 z14@}T+svFemurtb{-^)XXWqt_&SkxET^@uFtUmCer|#aqwH7`ft(h00fXEO+s5Fs(8Nq#0NAMQXO7lJ;fM>zTKHXR2_#}5o41I>oI22rUICOY2>S(U+PM*^u z=Nk$X1_2X-rp5%3s26H`B(JkFSjfTS3ACiWgctf^%$EXi1&9G?jnIi;f<*LB=s%I5s%1tdFTAAIs<{Rp z6M+bZj9FkPxan}{a93?IuWmrV>_p%ISzt&g;DWvcA~p+?{;EepuT=$Yq0p(31UY%} zRulX3ZPD7|^>pZZ>awgl$wN0>z44hp{lbs-;kjpCL^>nlL9okw@1&KCf*9r!BADv( z3?Km_lHQe4LFbIIYkp>@#)=Hyy4zGJx}{Q$!dM zuq<%RRiTU?*JdOLDvG&pHcaTMRs@(Kw#Jg6{Xm92F+@DmI97De9lF74#eJ8ztB!KI ze)F+ce&pK-0CqcZKSP35=Jks2-ES#jkh7aXS7@Ay@$xt!F1Z#ZQ%*$a zOiN@TIEX-7Xg5n*NXWMLyXMWymfc~!mVQWG8S*gv()-`@^{;>TM_X}O??7E1gb%D< zedTnVj}O=7_^iz}BJ?0ueM7;ixyNk}fDqOzZfc1jkfCOtc!A}Yv_Opm`YeQcfsIML z+z*;A+pO27K;YhG$O0b5fCT73;0P|U_X0!4xoY^N#!2Hy$n0)b)sT$HYg2ba)WvCs zE`+M?1Wd49@lZ063zx&2kKcOv&g-_qbU54HKiZUWvRd5%6C*k_gHCW(k2r|H!}T3G z0K?)TFkMD)Ng&I`$)|BEawga}hYK)DeBei16#lI;$odRfLXYDjNaW~-074$wxRh|3 zEpm$HW&t2gtCUFF>RhNshdvIiupsAA}3$A8R^SQaQZ3b?%=3>KnfLOF!*S=T)EGku!{=fjJ?Zo@q=P)tm_WgtIykmW)Zz z%mW}B-!zCQ2vdtSCycWu#xCKm8n|a6Au#i*7Fea2>(-{bW|^_em=ea{NY2Cv2u=Wr z9NZ)8wc@hg z?z%h(A7qt&4@lcYeW5$2N(_Rqo8l{Wffx4)nt_>h8Iz#4NVtZQAmpIC$ueIg;DD=H zQ;!KDk*f!X#WDlMO3xv2FohSOD7b}6&=zI56S$k7kFh87%noiMkl6Rt7`!X+nrE3n zYh7&MfpQL+{$tlVLIk!XUFy4!e&i$1eDxb|)Cx*x#B^BFs;9fhl>{ZiaS&+X{X>_4 z1=YM0C!;by6q!R-hP8`BLMi%|Jgr#_L;wS^zEuQ(|NXGo!X>BPpx@h$Prp_$r(fl z0Ys2-i578RM#>1w6B6Y0^HI%x$V;-Lqc?+C4Mv7nj6E43CJh0nO$2rkOy(Da)oHe7 zzME9d=c)jnGYk2Uu-ft+5WrPN52qp#ir{pnm@pOUdS3TQy8g!FPrdZ*SKf-3%4PjD zb$Jjz$kI0Kr+a-Tj8ro1C!1zlb+qWM-4P%x0g}Q4=ZKMX3Z{#uF(+{Iz94{C^~{hH z#w;u1yp9epYis zvRakE!b+Dim>Ll##<;~Y_~AA;x6<)?SZ!~<=hJ`u@BXe{_2*!9VahNC=5xmc#DK%k;%=ZY5YwD{EIsGjIJdo8QU_o?KM}jPn z1+#z%?q^l=`#T+H-4yH-2s(mAE6!(a%~HnJbitp3Nm^dS!X$)%P#8CBNrg+M!-J#8 zo_g=MzWH~(@_zLrPkr~LR~)=c>F^+(oi|lC^>H>rD4D_%lM*uFtZ{{fpp?YnhZh%@ zl8_MQYB?=EWP%8}?KAcnA=ofW03nE=Bh0h4<^Ui9B~cbkg8NAw{Cu?Cs6&EP!NSf6 znPQ7(Q?ss+>O!0$a26m0Fc%>(CqV??9;TdAUnCC)Uw`KHufjCo+tSdwl*_RG#nJ5; z^!=oB^QvBC$wr8gK>YkHm>A4~FtV1M5Ki~nrNsactL2bo1$Z`6O?a`6`1z!9ULNn7 zuouCc5f%@_Lf(mR-`Z@!-jX9?ts2AIu9LIV`sgF8EFuL;*&IIki?6=kcJK$QwSnZk zsdk9!R5CfBf)734yH`WZ*=25kT}MplX5*}?pa7YnscW;$SQ0S-xF@C%2_r%?M}$Op zvTG$RMw2WU8CZZ`)wKmA0YwlHm~d`3HCOlBC)M4zJzd0IKz#p2C{s*pB$VFflE|8| zAS2|=)1;5zTr+d&$f^JEFaPr8cJRU0>(=*oK<5g&DTT<#$(V6&wyy@@U5K`q zS5=&X?&ipV?)%9S1Ci&L)R`kVFFSm{04**n)=V9eAh-*m2-aC2d3Z>P)pgbP+nevb_43^x+X~ec z&{?zAlSDiZ3pF)0*w5M(Vgh6o4!+o+oV>O)UA+0= zw&atD1V8i$>rHjS#9@5=aC@(3+YpqEKcxjqeOU-`A3s1bHGvfcPfR=GU+H z&cMQ}_4Zdj@~h82`>h|_ir@T4|G{^^{o?sJ_bk<2m{7Q?ONPEu|Y4u40AKaP!%n^wBUmS zdNr%f`V9L~Qv$OH{6a<$#9GbGuU+jL8gnVD?ekxK=_mOEdGh9Jx8EI~&qLx_EoU~M z)^u12#E?Lc2&bwi`Q>2PSD=-2J10bLP zwc0%EIO!@wmnf9UM3@uCG&mRwLRih`YJH~GoXL^Vn-gOqid$@AJUA$rF>$}We)BIs z`^-=Dvbe0btu7D32VbUx+bJ=CLoQ4Rl&H%geD^LvmvCwh=t(g6UU(6PE(`(w2eW~Goe6UNoRLq}%*&|y*c^{S-d%5z`)yCz^iSik(C$M4^{J8DbFNRSgLfN*5# zc_J5%O!k=ZLQ2aLE_Pd8M%6G*EO~Nf9x9k{0h)PJtL{M1+^YKAv{qvVVITx%n5)H6 z7YP?tZRjaUrzeoyy|bh|8>Qp zKUy!o@Cv7W5j-2`f}{X_$8&R6OBod~Se2pgtt~>h5Znmd%=eS7dyX}*P<#!TnHO0s zchQQu`s|Jj&AqD6)q*M~vfTD+vq+go1VfnBqZQ1{c$v^6^NR^O@g%sPweOG!-NDqD zP!NdG-5)wC>rH25tA6{Q4}ADrZy*=?p}K#94rfBR8*3&~z>=w|>)cXdCt`OqV?Z;X zsuKYa2!aq0`1z=-j&(`d1j5LK@J;{;05E>YzFKn!#^zql=epp8gi*~|u(i;c0ZMu zr~m*U07*naRM+J}_^zltj9?CCh)n2!xSv}RG&cgDXG;RwY^)lPup%JnMc_4If)F@Z zM6Ko}5oy_=0f@Y* z51Fc&hLsxJ%=(0a-X)B2Us~Sv9^n#w#)v+MlOQJ`hLjKyrW*Pe-%ko|oj~8weo_N> z^l?@-YZf3bwTM}08p%HHmI#;^tBGXNplX2!)^f9!EVvu>@rPGNuvzugZC`lyO{gKX z4VcbbH3D$+rr!55RTXzfpJwaQvVDqNz`(~adY7;yynEXE9BH*4Ui-da3t6d~nwNwu zP%=WaqFH^d6$yuq_LD~FM%9P|i6lbDU{W__^2`wDaZC;vfikAV;Lw^OA~~#9sqbjN z*T)~(OlBhe`r*eu|CevVHvW%)>pywvJI{?{+jOF81|EMT$*rn42Up9PP{PR%h(PX) zAc9%&{#ok_#UON1OC?mmI26@9XG#f6W+aRwu&VDzL-#JzYT#+MC9={M;Oblz5Mt}; zYKTx|5tqg#b;zUu!;rwC&L%?akUJ@b=Gh*3WHWkO_1pCmAAIFIKYnX)S#Nh;9)$0T zYIX2*)~X&P-m5c#2<@gO04@j-KN|)Bb0VnbV9Vw&d`m=NZlUxG2&bCW=E6?kgkEQB z<}DHrJ@8ITdaaug7`PYlM4s6b`=r_xP;G>UV2n%NA>sw5c{W54S`2@QsdSVRWx;;k zfoosn@aFqI{ilEZ=6d0qoOZi?JM7YIfNrHwYt}I+!r7>quA+guC z+)*5sRy6b4q7{G$k({pPHN@=hgbsK?$#DL7$&&%|J6L}Y5bz@4#^#c@I4O}!*&=JRsxb0J^^LYS+nc?1iG`ywWUYUXbA z+PaZEp?3*q^^&p94Pi0xBw0*yX3)%cqnY}GNC()gQxZs-uU+k>ND?fogXiDm9q8-N ze*pVH1i$B(-+y#`dVX?VuN@BK+?c5pIzO$Oo=K1snR{Xs36f3V^1PW#qAuZXvIrZQ zt91#@VX8J(3ql(shP+d45!1%J0TGxm&c6svil(u9Nm$J@W1H0hI>G20E<7EWs{==< zmxrQt7*bydkRE+>&B82F4sLw)uYVY-a9IzeE)T+YOIcg3R@3d1>9FvmkQjgRNT0H0WsHHdb@+i|=JO^Qme{;OI@=%~Y54RH7vvG>J!ko`DzkL`&Fj z#HlCpxwXO;Fa7u;jt$4$EZ%xV=m5fynTA0CeCPy9YT6EZrvB*#S~V48al`!eYZ`#vr{_bwRklYpGz&l(LW{ zZcT?SVdkOBee&F`o_lfp>H6^fTYBSqQmwnaZig(HQlbXdriSQ1Fbs^~)7ZvYt2%>c zfqUnzsfA&{-TI8p49TN=)f`|!29%5lrV*J0R#IG>%*=+oY}(xIBDdBNEXxu#5CRP% zP>0%_0FKW!WfZ}ZsU%vhvYV}j;#th?U?tu5(XV{@r_=-1K4o}9O-Y8H&}+acrJj0looVraG;15Qv1ft$MLjA&jmBD$)& z`#KYtA$UX+t6Iz+3cFkga|jU;%%L`Shy7$Z6CjE}5nin`vUf>_?doK|&s{or;v=8= z)SH|TT$I{sy_v?TA>evQ=rGM%1{ueeG7)3SoD1uM>4h#~7C7D6ZqiT^#iX>^;*J-_ zrT_@Y1c;@OyETWBIfkORcyN8wkuPc0K#^OBpl%60^Md^Y07i6xrtS`Ng(RfvfS!dV zQ@=`XcI9yG?zta6^zr}jnIB>7UDkuD%Y*P;R4;tvmCdGRf!*FVU1GtmaC4id2IwT% z_bjp~;1NBsXZDl5?q_Ri%)snS;20E8CkAF9a!05wg1KXCXy9gMQ&V9WO03&-w${v= z+UeK;j2S49A_N35tG8wVes8Z`L19dp7=W1oyrhH$4^~CJ9&Xpa@T>pvvu|vl|FLy^ z%9M7(&>C#lS(wb61kQG~%M9p}C}#w6LTIxlfy}Unpgk_l>ik<*8`8DrG-c1%Oqbz+swnvrR1`ml2vO6N-R2pcx_z8K-LdSwkK| zym%!Y!3bE87uW)XGcP4nHD&-a06QDC%i#xgfM|sqz*IFcm|G%1aA5>QBCO3b!JXsU zuQ&jTBh;UWN%*PtW5)dH@b31|&GB0L{=1`leLCM^jCBab9?k4T>MeG&gyy&u^ zHOnC>0`QPb10bO`XMp?1H5DYLp%Z3WZ#oBC^`%?&XVZSQ?hc;(=pX-ovqvuL!PezL z`0lFRz5t(RhNiGtWnpS+snFCk)bMj{2)+y|!G&Q}0Kl4Am!O#;dyMZeh}dY3mJ);v za_CT1;~O8{h6Fjvqe1{H@|hk zu#uF6)lA)WnSaLP0f3MT0lEl@fL_4cE?R-X+*5%4tWE8B*J|@53n(CBhUOO2W{{3*xM=82tu}Q8AN< zIKyV$JGMuz9DM1y`7P-K0PM&9p@;PLo%8G0w!8h9bE>nBqo&N`zM6UxG_$!H_=O&d zLj7;kq>f%Xz6h5O6t$Zg64a*C*y35r=tUMEj+?9b`P9}u2hm0thK`dUAnvPGHN+q` zco7U6pAdrH!<_eOy zR&~c#tyR*W$~1JL>Wvd^c9D zL+K+P3HweEe4cHdO@vyr)~sY|&Cd3X2&TD(mEOTr)y!5sCPBYgae+5QIQA433tQ3Js&u>kzHYaJgE5h*PqXGMX4aZ7__0YNt+6(P$Ol#}3Hyx9plY=#q1#0( zT2qFAtoq#ad}{GRpPKFFC9f{HWg&+NqeUbdGGi7>LXvphOUaoCm`Q~5zDd^ zgl_Jwd24EFg6?MMzOOpX8aTSDKFyYRfyYj>MnlwKt_BF&90*DxS0KTmPfR2Xr3kU0 zz`@}vQ?0yt{)L}%Tl~6p`;I>T_(9*pi!a{!rC+>paxyU^nW=gzk_(4#9`WK~c4%s* zjsQt;C=~O}xf+s#yE(+46{s^pbZn|xbs>0H4e1$!yD+I*N))%i*4)9}AhxN3NK7JB zvJfK^(K)hM#IF`yWf6O}}LraluA0KoaEtAWq=N{H@` z4opal%oM2tB@;6ag1`>U>rH;ojqUw$y!q6x{>fW<3P#no>bmjtbbsxk10qL2VXXTq zNlM27kYq-dP|3KP#T8f*A^6-P9w@@qozQcpR;@J)UL^pCkO;*IHxw!v37rtfYF$Tj zbzvfa1y`1c6T5*BM#^88C>JK-?Y6si)UEpdGhcp-Pr<0O^K#>cfBQT4{@(jjf6a&$X&n zy2PzH5t%J%WtrVUgi<0mAcU^4FpdV}tnQvNC#Ha)i@aoRJ8TG2+%zA_K??*F7=ej9>;rm=XcF2!^i< z36M}E(2I~WB|&CrEg}U>gdBXgYh8&rKM!3vxGOjd=0dA35dkojocfhKa&=|QAN=)y z`hWeaPrXg8nCtN56aC$j`=<2pLn|{BL95Li5+S{Io+VC#QkW3>j{8i^!8nio z`r7B8erv{nuUn^QK7Ip_gBt{2MLZLJz#F*=b{!2mSxyvVKfGd2_mT`{WZJe)7d{-4%v* zvY&|=VV>K`UV%{6!JG(9odp-!146A%h><8ngl6s+0X+zj(~WKp;6%uT`^ipsH3^kW zW=;S>%0PeyzFB2rLa;82GbO>JE9-Sh>s9|J|L*u5=)=c9GQ4{0_MPvaefR@6Z{67m z*qz&FrOyoB)b`bCvw1dCZ_T?xNT?2Kj)bbtOd5hh0QcA88qnQyVl{Vlij;GJ(_I@U zT@4J2vIGbm5L2SbY`x0F(4~ZchLAgc@}cdCj#sa}=gWr7^85=_>F8(x z2XVW9JaS@mYwBvYAGJ*_aH|9ns(`>)t1(lYa75@qOHm_4a3H2Q?Est*nXy(gv;C-j zFV-AkiM~Prk_Db3iH0QA6*>1kT{|2mtm{WU@$dfZOYcA{{{DyXE6=}rbr?`^Gi06S zvt0!QFaw1B*ru_Oy8$)>RYe3tN}0n|InN5XL|v*H1boM!WHtvk0|!Jz05wPSd9s{I ztC@LXBtk?)#%4aOGZXbmK!8#%$&aqAQT&Tv#dn|&m-VyMEef$yB zI#+Mge7b8X5t>zprZ!EglS-ndFwWX_?1(v0KvmqKHg7G$LNQc-f%m6ODFff-Xr)I8{$QKl$+C>3n|U$zS`UKm6i5)`t&&u)lln)}8O4UEOZh zn6pZ)8%ejNID)W7&oZ~oz5JX81cx|FLAZLH0A z?(U{t9eQpC`?0p>^S(+VBw|KnWTCn0Tn!Q3VLvuRh$$!&5Mm;%>f_kDB3bBsY{$n_ z-wOoj++)9h%s85F))@$foSPc5j8lE|$*W`CC0T#tTmDYA;oo;rSBbIy}CuB)sPUt0936c79mC0jZM``W-}1RoEU5nr>b3c9 zswZc4oRx_PAtEeQv+edx5Jbow46#-djHM2+(Be38XjMfp33Z)F5Lz8np;n)& zo}SGoXVu(GB8pf+LPSvaew8=dp0gm@!AfQa%JSHwSFT@Kulm(rerbB~g?BVq_0?PL z^elh!6W6}^%3W_Z&3^Ujh6&DhRhwm|W{!l&)Gc6WK%%%3Bf>m21Q4OFlav@BSYlAC z&(-#08~1gblnEJuIV>XRZez95=gmP+%q7u!m6RwKdG8~KF1|W?;k}3j!mmK}tOIvK_=7h-q%F&6#l8H*J=MN+%^V6UBx( zvQ6A!8rwXz)~w4c7vokpXTsUMAIfUoF;ky2Cj#WM$sc~-wY^VQp8WNv|K>7l_vfQ7 zZ-hT*^}+YHuYdd2wau0jUpZV^oA2D)pPx?aA&s-{XC=U#s0ae!*!*NSw`$XDIZ+l8 zAqPN00BFr>v!jR1z1#zQ|bZWLMj)Ez*pIBtjVw5V1DX zW^*+biez&$0|z%>^@2>2lRE$cfUY_QKt9 zG9qDf7`jY3wWcM(rswnKr7N3*;o5eUiv00s?>)di0Kk9q+c*F4ubw-;vpd`rHxjg$ zUOv0|@P^TLyLp;b5`lSQcJT9k1$RPh>XL|v3=t4pGgYfqgBJsK5!H)8jDY9>3bQ@fX5KEJvi0O;ZCo0H@7 zyT|)+*S3SSrjxohODVwGFjX}NBT2u+u584_^j)>S_iBlwfl$3J%Xo$tPIdcR#+cjmnA)2%xv<4%u`hC;p@>sU<) z0Du9e792I-49V0=Vl%&WGD#K@LO?TX=Gt7CQi6#1%PEzTnyQEiW7ii*1sgqiqrX4l z=f3nd>SEqh{dd3no`3TfPv5`0J6tC<$>?|QonJrfjakUgcD1U7>|<`;sfAz}IkkdHbJ$&jn{`mj??1S#X zQosEh2Y>VYckkZWKXf#l+@A@Q0S^yXYF1mDs-k-mnyby#=dre_3FBs!%>B;s+^rH3 zxx1^+O^L{wh5B@^)(wS_0MT66h59~^&0YB6>j!R}T9kNsvec{`?E?miPV-)+au8_|0#BV}GifAu-52TV`w3j}C_F z&{UgQaJr)p)70v$ZoZqfsS8oprLM4>Nn#)}q*fcKN#<$Rp@*(32b;sv@!fl8?|jZ?5Q{u!;70ed@xbV2IZEjPwsj3;I z#HFN^DF(t$s6gg!O@+zKNNmWIIxeyqwgUk(?z$@<_|s2)?Lq(U*Qww9we^?3@$IwY z_UQG^`K}H*jk{45KqMuqa}B^A5w*FE`??z&AZqi{rJPw3Ap$t488SP#nRdBI;@XtC z3Q#rXP9D8_wB8KP{^@z|L24L-Iw*#)a60=b6>yt>zil4_5FKy&bOG*U%%{D9ceV(T3Zjx9S&7oDB zXA3VGF(G2#WpfvyahmtjR64nGbmgE=oY@uEJ>uqxKl#+Vosabo{=FOD|K9T_$8{X- zk%v~(tRg9+-nzGANh!%RH3TO{L}(4BshK)6x;ZBX08U(z)Yh13o+e6Ax^&~(O~!ir z&goN6-W=np>qy$Ah6FY9Nj%Y*R$ zC-o11{l<9u((U`x>B-*IA9-jqPBUU*adbV~&F0QTgha$)&nH?O!Bf?-HD=1gFm%Jg zD$Q-Wc66`;|35zS^SA2wC!c)e*>66(-}~vwi~v^-2SNfsBCA!y2~9w55a*w}gM+)z zRn-gx7}C+5r%S>Cf#R^e=nU^G4=H<(v~T3x;?K z0NelokkJj?-OP6T<_=S>oN&8ZNhzByQ^JzdJlo-lw7d4{&%U`}#dkyf<6qm}Iz4&m z)sy}CzAK4AvWUAOf~g4;5V|ci`dS?Tn)+O;qlxf#yWXreLq=!Z@9U#C{$KXqv`f~b zNE0+OeCaDkW}ERQj13U}29AIIrCa{XKRvBV%Y`f#gC)mzcC8bt01LB- z`Ms0r^vtR4)2DW3BpLM18&18lclj^Bmrr^UZ^C%=iI428p8wJFudG<-^Tl$W739>; zbUNwspgFU(;-*B?>1=CjXEvGKc!~z$>rS7ZbV$tm-Hm_t=g*(?Jl=%y=}+Er2J+?o z-Lsbt4(6*a2~ryRLB!8hM#OG1nQd)%X)@_1*X?uwyjZQyoIZWiPPaG6^p*$y@LS(K z>3O^f<5M4-+;RO4KYH=(YNcHVLzdm$MM}x~>88mfr9_C6l%`$RCEDKVfRF^c=|uPd zC)?ls>)n%{#Adw7V*`Z0`QxcC-f?=1U%Rlk8iqvBrIZjSlWvkGoMD-ltL~;h|NoAo z4E$urzxY>=uU`F&q#e;@GJzpy7D*{>O(&9dg7nIK7tXxz&;IBQ9+(@hpxgieAOJ~3 zK~(o^G(PwEM`8B|cbvXH3q!(w$fAmh2{E%w5?&ba`a3`Nt^e?cC;d*}^6`Z)+;?Vp zWym<2Bn7pef(pQ@`vY%n&*sCl)ojzk$to%g0OIXZJ3x`XTdRN3$yc zAOR&x9nH2U*IzdSxYmO`zxwFAn_rqdez3n9R++P%-2qlXkvi(8-S*D(=2P1MzxhDO zJHK^de#=iU_Cr6gAI+|IxL}&3>1?uddTS@`ob=l~j&WuBo)->oTP{|4$il2vXK5jX zNjHPpnd^4|HbD3rJ~oW-H*nnhso&neyyzE09$2ypi;9<%gB>lQUDjHfU;np%@PD7=9Nwhy(I=jI?UhT*y~VH`*pAW=>#pYKx!XWr5@?n9)KQvF zrrXm~*YDi@o}2&Q|L`AAb{22SxcAdvymapJ>R^#qJ@;9d)m#D5Y6}GKL2i9_I!cqS zn@y)XTi4xm{ZIb-&rW(0oAD-(4G{i@jK}`<|MKG>Uz+bOhb40_!Xg~t7iX`j@BDT5 z2LM3Diikkgt$0e4?a7%Nwx9poZ=dM2-pKgK4yh{S0`mJi~`C=`#N z*a5(@1kE!*0!)-9lxAtRGrRHD>wf%~zka58?^xBox!ID>*2bL^#(^oeEjBd~| z00C%(h%`x)?dkTJ?YF<{6Pg>CWu*jb|Qy;MU*yKd*ID-2L$9FT8wy zxi`^{Dy+hef4=EM%L09jgs@5t{n_4GE5N|vFkza~bf-IW z)2W~R{U03fEPtu-;1mDy#h;vC>=p{>{13t!)fH&{06m0-826nJXh8x@NC|0z-K?9P zp51)=4bS}5?;rO(e~IzlhaWrt^2OEul9!nW*6;>E?G^x+1bmzLAcf9xQfA@#iB0;?U0}t(otfSCj+=k@-D^cJz3jzAN}g(bMt;~)CYuB6@9Ys2poiGO6{=P@{FV2V1giR2(ZLZ;e2uFh7krJu@Lg=SuD-87*NsSdz2WdjxR=0Eg z_IuuU`(JOWq)gLPqOfTFnt1_Lyq zG)bkP2pwXVXqwX2barOv#@pZa(m$TCDK_JEjm?;rOuOaO4-r=AqJdH=$Em}l-qGAJuBYU}LB9Aj5Q9UDYPnpeGFc0p|HpimJd z?4ZIjtcFV$_HKR8eYZfdLpm00mGG6;(+AMM)I}P=Ewb6h%?W6a8B=5vV!_qDDHA*;a}v zR9Pf5_rqd;e&)72@BidOuRQzA@ta~Z-oV%}!e5W^TOWDSiC{01LEPUDxy#3zK?_WF^7MXj| z3{urUjCVbza@zR&%{Y<{j$?@$s#xX6(5BKPpae9f$yT?0{q{Zg-|=7n^YP^nKK$fU z&-~Mi^DFbb7^G*(3JhKuB3RzC!<(Xx#lGS##N=DnJeC*22HwuK=<$v62$$ zu{({JO~VMaa-B6gXwjaL02By{;|F29LtsRkJR6fUFZP#jd)K}D=Z>Qf*~h;0jefZ4 z;Gz*h)gp&B+f+p=+ojMT%X0t9x8)1UecRq3vIN`AnF1a-+9@OJUQ}3epD$nBzw><` zxcu^Q@S%4<_{a-CdULLflog4>a#yS22S&^ zfCNYpC6Of5jx-S@QX)-$9};OoB?2N%2!u*uG{l088UjpR6~PWcR9QIZ<$Q6&9q(LR zK6eau*oMFz_Y#p0f-HZazTqOp;$q2K5MM68ed(Dmmx z*#gaQrBq!h9ah7Qci#Qj;}1Rk{kQNqo_jy>M>92%t+S`)+YI&b{ z)E88w^j~op&;UN4e(*;_g@#BQ9IA>+mgRhT%X{wIJNv?0X9obd^8=r{@ZyEl-inu5 zdevO1Pcen5f06G*K&XU(1XN5xKx5AUib0?;g*_PL3BnH07^pnz^_s#%-o3p4jt_qD z(o1ilhxD~?e*MCJw|n-|u)pBNpgqGNkO3IL1|+?Knn`GD|#3O4`JUCe6aZr$8-={CWHm>4!>r}#&jCMn)~6E^NagG`LS1?{n49i z1RL-A(4*&GytLZud1d*Kpi(qT+mgo7&}M(ftD>O&v=q`;E*L3-*w_YP-L1e10IDD= zqLQUw_BX!cJ@bn%y%lx~z z>TNNgFRrz33U&;F`S!V5n z2#V);i4rS`k|1eHM*a%tGZqMBIbe2+P~ni=X)w}U=wKB_(Kw7R5D}5w z50@|R{nm#bxcK5*>mhB%8y*`Vyhg|SKmF9JFI-ve54l&dycjK68%;_}OA1F)=n*@9 zi-GTZ89bye|~S6 z54>Xa0*PvhN(3DO5$p?_ojtf9dfOOlq7#otAAw>(ZE}W2t`|Z{q|z1xAgrSzBK@kr z?e2T`-fS%V@S~4C_xQe~Q5l+mk`;GX5Z5gf_Q&__2y#XJ0JMMrB`=X z2Sa3sMyeh}w5EW+Z`@$WH&XndB|YtM?8G7`S6#WyBprV{o_?EmABwT$A>Vk{yXP0* z%=20e1^a_udXX%~e!$sJWPTzx5ZL11AuKG9AfYu{wN^T7&O}w1<9&=*LCH^wWmkwH zsH!p#eSh2C_w1d0)7*lOJo?yA{`sf#i+eopW#wgp$N-8Uz>2Kc2%#y+U-I@4L=J(N zfUE>0A$iXjL_)_xYJ4VYBB{`NQ6+N*5bbcsntU9xiC-Vgi^cL?58Qw8rA-U(Yi?|S z@R}R%|Mb^i{ppqEe$KY_3z)wduDntZ1XTe6CAgqXMk}NR3PRQT(Dr)2E$kTG4X_?sM+u>8yT9Vt zSJ3(#drYGQQAPPp#ll%`Y=1JPbod_RGImf-+J%<`CnBSy#2n1_s;J+3T7|hLxVuC|Fc|}NR9C$ zMGoN~1@eus(CDCRr0CW1jbywA|7}Pb)>niY8N!-DqoAsibH3~S@4x)YuLJ;J`j=1s z^FKa6zqHTuURT~g4jG`xp-Muion?MT{4aIhOFpm=DIs=99Z?rVu!X~*hQ*R_6dV?F zgltgDFw8G#0}mRe5bgW^zK1??_W9q01D}6m#s&zlq4DMa;hRtY@WNtu$SdXy%9RUh ztA*Omgrm(EM|`i93&&7sTU-@L3wX9Kb_7YZadcJU=;scG7x()4#WxNBAA01;SAKeN zwcqDeX`EKeMM}l@nu3Rg>IMY1jAuPoXb+Y>4jMSDSa@WONn@)KRkrMr+P+y;nECd5 z@4NEq8;=aV^FyD${OaX?f5km(R^WnyzWbM=h)8<$X5rBz)jOqWC&poijr0%Hsx&M1>|+uG~oIB}UkQAC8TKW$Hk!ZPa6@i)H`W zM<4#l4>#rZ*UH!c;WaeoUMa!iC|C*5+U~oyEft-!shp^+r_~D!)hSZqn#}t1#+V)I z(T|4=#C+R(?tNp01fTo*H=g^^*~RWEFD)g+y9d;)NEqQCjP)zTa)3}FK!`|Gpphsz zP!knvth%lU9`*{Z#tRDuKyeEs_xar){@{h5y%7d*-zUFt?uGL!%Mr~IrU2)Hii%e8 z)~0$8?c?`{bs#37-5VWRPZ?Eb@vF<-MP7QPgsMWTh*DKVl|K1#hE|#`H%hNN3SDs=I#f-c=_CZKObZ$M+hMR6ckiw zz^~#THRP9CA=H$vk`vJc##;ES=Frw5z;TKUHkm`~T6G=unPCl8Jy_-a^RF*)ribee zF76NWLHaO-Kt(}B^~`?H{Dg)IH?gh`ZTdt+9nmz=r0n}d9fe+sNJJ%x6i1W2+SITl zZ;eumn&&Hy)~|}nUGKZ^@++@HHvhs?UwZE8mll@~@}d{77gPvkn1M8*xEyNfpj6U9 zff8a@CR_B+L{myzDQ%^+MQLURK|{w83LXjv{*pn1(&Hg~C4!2hh^hc0a?gVgoO@wY zP;v5O1BBPaz{%~4y*{rzE2K>m4KlJWYPNBkasIy_5mUf{O4>u4^w)G#X}>*M4?Ln( zrw?8KZgkk4s_yr^f9{vv^*-_Cuf6pA#pQmV<3Nch4;Xj(1gx7>Wr5_Ui8leTf`Wu` zJBpCeC@|Q}X$=JrLBfawjclb}OE7-6ipaa}fB!FEMt09bpS}3X<^G`O-p-QsgbPtr zAc0clO$`vHMix$SRFdnWiKZz{i6+TVAvrw?AS@xVk-IehghLIjibQ)x$KmHgEHSOm z2guAH`qYCjKl|J-X^N$8@1MVt=e_g{CW@-{Fd$ZxH7;1gqFrNzj;JeBPHC0`1yh=( zG^6SnOprP(!ZJ{#QZ-lM`V~=&C`XfTG*TPXSj3RB&%C&D;g__-X1sM{1B53(?tbuz z-3yCh$(&XEaQWuA7gz(rHAWX3c||@KLL(gz8o3ZgI?sBnt8Dt~1CO}Zj9O0N`(3mw zRX|mh_dIa_`Cl$VrjxfFTwdm7mLU$;4FUvO+JVM-;ZY_Ld-pgmhEk$bavvzv(a=cA zgNCJ;;>cOYE??>5*kWroXt%z@I3X&Z{M<*MfBF|k$R2&_$>*Otx7b}~Yatzl^Y!2e zvZ9eDvvCB0B`?OXf0EKPrD?J=lV}ofI4z`*TpBHP6zdZ_^kI*Y4-egGEr|gK;mq`z z_bCkujFy&!l~&=v*3*zE`fClL|sh^AfIO5L`jAkD~t zFwH1U6U{<9Em@;YzO~f}R-b8ny47L(w4%B|BdoTUwcc^>d#}9qy0zlXcyq@F2v2x? z?yKK;>1VskgPePDQM3|}LqJ$@tdPQn5jy@s2!Cyhr~-#gH0&r@uV{YGhw4v{AccqM zU>j?U>;VK(onQRLv5*gZ`mu|z?)CG*Pa75h@248=v%Q~J6-6V|*XD%=7qlZ&8%CHc zV-Q^@Y?FxGrKnT6%25sLJ;@_0@~~G?KRj(RcXi3I`%9G5@$|;M3;V+&L{WyK1ez!c zgc{i~I8sC{DYTHhL^MgsfzWhON+yjuL5%c}aon`dUt&t?M6BtzeTWgdOj;OHZP)-+ zkgz*g`Oz`)cB7ORKJc;K8|cO)J|YjYf8ljCD%0+;K9#)^k>hUz}Z!sQN{)cPk7Mw zo%@%U!%~=|ZA$GR^NWD67J_4?gHYfws>2A^>!r(|U#kggl0@P;qiE3h+jg`kAx3hG zL#YD7yFT!~U#JSEty|~2%e=A^g)A!sO2d@Hp~09_B!316cFtE6QS6e3h3rmBZH7pl zcA2k^$xV~%0ZkN+@_7gABMWKQb( zj}$yxq?GrNXOA3QJp1#P#N7`*bmi>j{$LsP5&)u>9V3X2f=$z$Ao{7zjHTd(U1*_{ zW~tjsH0!$UuG{XqDw9SgQ5tn0R2?sjLx&w}i-@|ua>{B^Uu)ws4D1#5&iw*YY{pwU zHb8iij2qPbGJ(yDvZ=t5{pT}o3!!IT^nZKsPgzS1W$=CtnM7aDW~^0iNHY-oqt)*f)il93>b z?w$L2{Fr7p?O!?=76V6-04VtJxg!)TX`;3Io0?W(L|sazf_eZfrP(BHb=_8%rd>Bp zX_jb`(zF%{fR?^(^+5N+1xEqk)+bo^6-Iti8-6YYJOqI7&iCJY@#U-X(Ulc zhZMDccHWpzS?q8PtROeCOh~_Dks#X6Kq%&3d{~m)$g|qs_p$q5`{}0L%!!Teq~E}Q z*W==aMZe4*8VqpJnro&b=H-g%NYyNXhsM9e;DSJeM3~6iK8f0izG@eGarF%bP(iVF z4%X&jlYJ-y?f-}cI zO2+?01d-Ss0#RjAMifF(6vTum2m~nF^cHigm;mnUCQLAjk-D=aE^vb%YCrI>?DsDJ zye0AcOP5yjmGoJemCZAXBmW3W>4-+f2;h3ER4E&!kcBN{Hl^(@ZFk*P*X^VNxUm8dGAZrc5AEH*!l)9JGGt6}%j!PQLhz-PX= zocBDivZ0{6+3jqbcL;?Wm&Bh@vzXZYOdT~8>{2(KPPS*$Q#;e`tx4AzQ|yv627}M_ zjLA{pu!cX6n*I2ZdLU2yqoTsf1NV#7xpTW$GsW4nyZxeT0Igy|kB?y<}EaGlf{76cH0d?6_7vw!QRRHg~zC zwvr*5lF7oI#Ra#flkM5;^v?Fq&i2l1w$*jBNw?jl?bL0hZi{Hv)}GdxSFxt9N5tl* zO*5y`eMa3BC;&DY73G2RYMAfMKl7!}U(FPo@m7xw5T4k0?fkr7X3ipFTV0Xp)^M<7 zEjFd(ZBj;ar;SJvLD%7#Gn4!7yXC=;z2nU3>7+xVN_pC`j(_8vmoYSs-&+$eDTr8S zqadQfVx;hcpZV;Ornqvc(!pp%;()4G+i+_a=<)nrDIRr}A*7UOd#k(Sj_bbo$lW*J zbb2&~3oy63$&-E;TNr*=+Fr`st_y#Y zYJDn{D#JsrVGU>01?dn-plF#sv3yvRg@?SFFJC#kA%!P4Hb8hXJ4wSQ$b^ek)} zL*+m+%G@~2i)sWOo4{3sE{bMmScs{^yY9N_{rA1Y^3$q%*P@#5b%%09>+XMb74)hP z#&LxLBFdTj)o|tV{IDrL@#tgo{blZ1Lkw)fQw{#KoTH@o*GHO%BLRl$&IQ(8=GNOz z|Mu7J=_aXadxtmowwL4@@u?ofk!AHqh7VQaUn9d(I{N?sAOJ~3K~#l#;MHRF^7$hG z;H9&BtNE%j0m9rGsI)k|9Gw2UWecw$X>N zp1n2tKU{>;A0Qyg6l0|1D}>T?Hu?Ae9zJwGbg2uA)y8`@0D*{?jOve<%gpQw>?psbG)KnBj;jH#Cgiiu1=q%!mRS-`6aZ8} z7My!9&AL`Gb@_kUiJKg zAH4SO{*OQIS2E-*W_|SlVVfIrXm$uCjM_Y~Zh_G~jnEkshX(zOR?L0g-(MUy;=$g6 z!xRCaYQ>mJw9br6q4(PK>*FP%qnu&yBeR@4zyELl?K63R)i5w;v2%W_A2RyHYlIX_ zu_!1yGOx8z8CeEF)$@h|)YZg6VG)+0A1+;9*UUfnrO*H1hcC*Im8IlOx%hx627Z1~ zVCBMC$!mzEYtp}gFe@;G45F%g`^*3Jf6J=4SPq$ck)bqt2Mr%)_dG?b6=iRk0bzFg8GVGGl*#WxGH4{_lIHV$C~? z4Q?$xqx`771qHP%NCmWrk|+!;qMBJ$E#V;YF=M~0TlKo=S5hCemO_^!1yJklNEbcC z2qDgB6=mk3AI@J{2Y`h|2Sp+}7@&&H`2~oj^Vw+Q$L8PI{Y`xfEMx@|pdn{f5g`Rs z0hY{?-6USGE@i*-stt{!e;u3y+yfEKM2NMl_FQWUh-p}{L2$IA))S7uM#JKASv83c0$t`_RhZLql~jRwU>R5jkwJ7& zYjYmf82blD#BDWvHmz%BygVHay|0+(V5x#@=6Nw+uD#>)m-h2&kSx)4*V&{1019AQ zpJ`iX)b@<^`=t~_JR3*`k(KI1q+j*IJQ;?hfXtlpD)Wk^7wM&T`4iA1?cmNqv{v>0 z_z0*NE`m027|X$frmCb+-qf(__l|OpHsct^MjAbV@#IrqUCaj_B1fj;NGV8agK%*N z+B@ro%;3N8x8iv!npygRhe2{BU5(ctsW|~Z^{d`N*7QJK^V?p*C1{>=XaP3b0w$y*ORK{dkQ5MM}EXtXsAM!8^L+*1PShA>n zSz4fuH@kKDSJ$k)_PK;QIwFc#>kvvRkp)frRexo?>s{Vm4y!E8CIWi$R0Igu8e6wP zr~tJtIR9mo_*`jYE8^4kBs0RG;(zV zMF@vrY5V~-$z2*NE_{N4my6XW9{FVZJM;ZT?g!-(DD}0W1VY#}qHm?^M*akMDGM`J zhf&Lk&7!@?D(3}rFOoA4tA5${i(yz~UNA4&uuuopL0zXdyebl}#?)dlT;&sKEu)P( z8ree{nmO~3mj}xyo_qv0`WZ0AK`fhv2Z3Z9(&(vnW+8 zj88>{MKU`Sh)IEC*#RmD7tuHzA zYT!lYRpwRpeSams^=CJTekGC(d(_`u-{r&qZiAOc{BDU+DL_q|+-;c9 zuo|2LnNv`NTU2Nv`D(QI(EC&{OG?$jltm2y2A08;K#_s%XjdmdQuh6|fKYk;lFEyR z^I{rz0kO4b`K?-4QW(H6U! zSw+CBYXf-@G?ma`xCM9^`9>?S6woRZZ(tDVMS7N1=6TKs10NU!W?p1oW?nKc#XW;w zi*pcpI}IruEz7ZDueB>ahG`mVSUkA$HZ6U0xmv+y9Q)YB2v1KccH66bwNEIRR2^UE z0wSDw)%&jZ#FLLb{oIAzXI14stD>v~tk4^is%6AzGc~BO7Ho55MsG$ze1lXFPy!H3 z*C=@ts!|*S5OGGxe)@aO&KSLN?Q&4eii)}xXKe+{Hi4)-A-E6=4|#Xr^F%K1&GV3j z8B{fA5ad29lA@Qrhbb@|mzpbtqkXk-K?D^=Rv^&~swB>*6u4<9iXvHEA2!)AtLBP= z+6bhFK5=Z1;~QmNm9SyC??L5}MT$?*508H7v)}oH?*hPT)f*66*8@=HffWc+irT^T z3#wwu$gvAkD1(w}7A4f7WUiLqE-9c9KFq3_We{DNTVP+|t;$FaDN}3TPl=dX1Q{A@ zlxwVd2G&hbRYfwdmi_wlHsh@y8z4OH@#U|6`A5%PTpcVS%`|f!1c6kz+e%uJD}0RM z(DuQy8{!ceG@~SqXcAmDsAhL>cllP29VdU*y=)A4>p7DekN{B!2@O{OC`46Ma$c?c zQopi0ABH?ERtlXC!>|GXQdHWSj<^1JZ+<6cjcXKH6~ry20$?a;_iUH+T*D~!*TRz{ zi^wBM4X`xD9@zq9S?7^M$+r%f*U^oL9Xn%BtrcID?|% zHhJq=&?Ddn+aND)FUp6V>w1=2`TIgEmhLtr^x z_W8$@n>A8Rq3Fw_G_Y0`Wf}V6VD36Wzg$UX$r)5-*~_4LE|L;#1EdbxcJy`P7Akhp zK0ZEC5L8igI;ct_H2N$+tgQ> zQM*cl91ne8e1gq5wy^=i;~p=)d^Yz003HPa64jJQ#M=B*LkCNEVN8Q+S%rrFVv<~& z!Dp{gk{12{xF6~$)-=AB=&aX5l>GQMQ?$DI%`-ihz6iEsuBKqQqmO^(bAR-Ee|~VV zuyScomTb+ZloAnW767Vt@aY%dA4_tr!=WX2AW&p^_$-|fR?cESDQ#~wQrRVPM~j#? ze)Bb}x6Ki~iV>o{s`ngkNAW~Ngt_U5ls1;3URE`(;*Rcb%_EqU1 z0;r+@kd>;60-2ytSyki;3AjVR0=ZJ;@C>{QU4t}On)8jebS*RyjRH3By|GdwnKMhy z^MeHdJpPr>KmFqulv#2HQSAqrs{#oNbx5dOIC0SQSm@fmHvj=708wBpecKhKeBizy zxjlNfQIgrxi&O@eMq$k@I2<|!9OuwlG+m?7cEgX$nS;8@1huMqxaMDiu%^X3Lo8%#w50QNO=ZRYWwN)~_-k(sUALsHy2; znM296l@B=zs#@Wl3IM89!!%K+xGRmDFEPz#r#n<(>C^YB0JD=eq)(xkFU-K)b!j+QsVWjk2JA4evLfM(prOcC|AvSBj5so>7@>f$iW)f%*|_jA7s#dL zaYmXY4#oK2*9=I~mG31Hf{zP-e|JC6dKbSrtJB z#VyoA9s$Op zXpu?v5Ibz6hP8ATn#--`d6()0ZE=?KcAP& zj)&E1P*H1~sVpoA1Sv`p!x~u3i#P@VlqwsxIX2GcM1UJ+Toy(tkT3|e?Vd;eLA&WA z6w5^4Z4)N~3oZK?OC9`LbBNY5;zgzogiGN(%nuT4zg(#(5CVa!&uswfII>7yJZ01f`d*%aaRAHH?HF^b?dvH=W5#46N5K?Q|54;cWK z2lHWnJ|z;{`Vl}ib#@jwa%NJc2}%|_L`sn;&iieA1>fs}F1jWL^~j&5-mP$9<0;zi zp7uVAu%?0T;pvaCuu5LV2rU){A+HJ^7WvNXq+$Z#mCIKWb<6p@-`(Hp(7OLv?KzN6 zI?SrP8jvV$O;knQ=OLt!C_xbd|LUhLqh*Ipeuq}AE=X%@hZX``uH014c(a%QJkX#% zBP?_RePfYtEWAofKF%Bv+{CKq;4AlQH7iH zHq0#$L`0NPm()>b-4I1>vPwl&8T$k!(Uc*|C#q#|WR|cAlyq4w5(v7%+i*L!E2Qvt zQ}G*9Y{qep4Gn%vkXc(D?mcjM1|6sJSf7VitgJcN}b{)VUgxk5nU_8dfOyq86<*ZX3Nc_F_+QXnEmPu+Z~mB5XF^^3>Bu1wmMta?W4=+GF4Qi+_|M z=dNQGRU$G|03eWKs>qOq{hV|p(n(5_5Q@OwkkR$_=ta79ItU7-@VsvHC_#V(RJ5rgMelplnxbs_ zP2Ohpy_$tldOz3;GcofMPk#QN|NbBP`HE1P#iUByq7H#3AfVj@#mL`~vt(5QWTccj zNfV&XYUo`SjwAn$KtU)qHs(^*2yfBMi%cp2j35B4AUJXn{H3&N9*rI9pM$k;(M4|c zKOCoSf(lq+#CVn_QfU&=y|q{5iYiNH=|t^BoxBoIK*Gs1 zAyH|sh%G5xOXdbB?*B*>`?;5^->(~76C*sL#ady3(gfH9RMBXbiqB2Zs_TbUKP;Ci z!7vDC3!3R9Dc9^%PyiLFMI<8JD~dpus3Xp*42YN}shf7r21ZBN7rH#kxQ~R-2xt`v zw3$mxT+02j^}CT!kG4-Z2d#0cD^NSMxE(}fd2rCr=ZRn#n6n~)uy!5hpbLnopez!4 zw<+h(2s2{B}j9SP&=9sm!FQHfP(P}1_3J3!A6IS#%VAj zKu4^NmOKSB_7B*L2Siq@)p9W(mVHVvte6J{1j&-RB;cXhgs7;Q8Nf4wm4QViE6gNy z9i}e#Sp|vGWHv!6hczi;LjO#Y(>o0@q0B*pELMIj#T!ru#rCI)DvFH_BSad}!D5Xj zUNG_$ZS@g~lqK=z>@}P5OOFi@9`_(nB*=rQKEi4hb4nCR{w70WU>krXQ%Gj@(@_Bl z?Obj^AU|RO+QiDk!}AyFCcZ`owNXm7Dt<8Hc`b!1;Gwa5V%@@%k-$3gK#wBf_^VE)B!k-FyXHT{S#(D>-;A?VL)3*a z--We1!HL5fG7b>Nk?yv;X<%n`O6$B3n~xa%q+-Q#YB4Bc zoB(0X2jZsyg3k9Nv$V-J(y$3?1EtZ?L6yAKf`~9L7YkkSWJ3E(=3Y$FWfqzccF3xt z0ziboen4(3oJ7m=r(>(GCH((l^MwA(8@aZFRHl2?C+# zj}W4Gjayrb;_DFB(tra3D@|OR3q~iP;tklh4vKY=6jM|yh4NwMC~b#$==&sqNFXX% z(PZzWgxY7pj*6SuCA72d%VIZs3|RpP5k$3Ls$^!t$)r1dW`;>skjT%jj=Iv;GtjVW zAf^BP7Yv(3q?&F1_0AgosVbx*Hy%Z5Up=!ejk9%x@@L0!_Uw`~> z{^Wb0N*FmMWTK%{jLhmAcx+WwKx%w=L(-fT0Awk-=adi;Md8%x&MNT6zQ4BrX!B2O zO0gr3dSBO;*`@d{+R>C=$fa3o>5*pX9#Nl;il_tS}hj{0uK71s);nrU`NxS z0wfZR48c}6c3y{|3WSg|t70Bt|H?8Y0su-hnWpJ1mB4B9IRphL6N7e&b>j7rxYJl8 z9tiAjkUkKs@{kckJm-9gN$e0ek)L|6OV`Y)845eH?7{1iRVU> zkw67SK*ZWkGczYkpC$lR%>W5-3x=#h)-Xv1#*|3G7$HRY2e4NMjtUKjK~%~5+;&|8 zASBw}nM@`r4sk45oZ1@X(0nE4+pP1LZ}VVye4&DbU)XeY7mpMmmbHMONES90QIRh_ z`ME#%_MacquCy5&AUx*r?Qi|jt!HiokaA=af`B3=&8!GSSb2)4JJco|^>wuEouS$$Ie|c2(?~+bZ;C#u zq@dI36cJFxa)khWtD&SEt(9Gk5>0*@UrooXp-)9I*-sG=MO9e=0J01NFAhKzIzO8o zF=1;%Sa%FG{PSX$LlbW|cW7ZxBl&)Wg$RPy(M`m|X_knq01*!rk(3Zbh(JM!R9HZe z5^|)cf`X`6VK@Q>l_M8;tz1Nrjbp3dW)U6;06=l*2LPmmsUu;S?Q|srH5P!5@5JH2 zb>ec!4z+o0i+sfh#Zaa$y8bPq2#^f7p#X_p6sbdEbyG}$d+0$0R))uv5KY+t(}Mpq^_pU`?lwYigfMwk* zJQ>EqUnJff2sr{M5Mh)JAe9<+fKp6Wv^}p9 z@a-Kf2MGa&ESRgsh-y~7^%@J;z^95>m~oIrs1qNVLK~=PFd*Vg&J37E)Exp6R8mzG z-~C~0dm9H;Q6k5B@5kg679d2S-64)n18rsOQZAP0BV*`Z8 zJw(MkW3Z%uumF!>oCM-6Fc3s6Z34n)$2Ra+)6gIk7j)t$Z9_`SC>H^B&w1cT5vcO3 z7S>qVPr-%?67g+A3d8G{$d?lZVX;#+)Ejz;ke1LHvU$XWu{*{#fxsf<+>U~bAp(k) zVlOLrEL{a^MT5^aTCbE`Bd=*_1Ex}Uo9cGBxzuadDko^j!Ppds9fDRGwFr}lXT?A; zx;X9EnqVp-UVp<4^YfP&oG+>f66GvJ;L%cR3!rGisQ6iXejgydb$aKB7@ZL?N*$}B3M&C;&;~iaQhDg3Z-bJz<5)o5V#^N zf=Us}0urva=|{eg0*E!Ngs412&n#$v6Awjcs=vv|3CND7iigNFGUyZeLopFI0$3oS0tgRy1YNT05CXzRuXe2aW6!DNRO# zD_ANcI};-Cz+1Eyh@5(a?d|P7y?_LwK*?H$dyvc}0&k)XYv+-OYV_B^IBo>V8_IdiJONinQ{wy@*0)0Z~%03*LBbi74_03Xgqkfbh7- zkn@?T>OvA?>R=ER5hPGW79m7LQdL$o!KbK}P&#G$9j(Oy&X%y*ud%(J3&=_7mpM+L zL5<{zAU#qyeQ1HO(F{F4gj9AwQO^Rb1z4U|AijSfb(E+}>D&M5JJX~)laA-o5o*Gm zRoDel7BKb9VuV&JU)X3XggQq=^(H*=F4tl{ZHs{#60D{vY|rXfYG!W}C50xJM~fha zP%}m-8n{>;g@~uoM){gkEUR5ZLLl6p&1Tctvp;e=fPh3m`0a1~>5aEu-!GP(Le4VVK@pIpN(M;MCA4x=AWJF|yGGEnY|XII z@?8iJ*{~3ih$6Mh#L_tI*m}|g?nDAuX_L@IOclI&O+1253>$4AV!t7JNAOscsHhB< z9vZ>I8u<>ko~TQkV`7hcY=H2%he)=R_gP0P76f9EWV(=bh5`}AXy_avBS2R?F-T$A z{%XU~QiX0ILufrqtohm_AT-8f&87fBL`#^e?HxJ}kc@6k2aV<|kunF)1qtn(Bc%W* zN;I8zRu(QG31K>cKC4p{0ko(fP)r0HTpKk4j}WRC;hUBm6%&Q{mTm>5Gg_mwwrm=L zJx7(HxFyuHETxLWTIIeb|2;@=LaUO9`g9cqA=K~*P&FZ9N_6wv-wueGSvpBcVS@dj ziGYpTbkrf_(lTtMXWRRC+1D9Q z+6xehb%P;55F{e8HwUN^VRKMWBs*~e&?+dw8_A$(ZI9Yik@#g&0_8;uHXqTXenJov zxiM;88nE|7P^r_m|3sW#BYJjgZNTfP&&!McAH9XM*n6;zQC&~qk7OuA_(8J%m4V>SA4u~K=2!u+1X(qnwohfPfUT0D-bvn^y!+83neG zsTGq)7}bwDa9p$x5W(bTOQ(s2QTnx48jOGdo`#~aFnj^IRvctE9Evt(+;pK+U#W#i ztF?`bYW>=u)0vR~KmtTlEN{5!CKZ*WX#zYbky;A04vH!w9>*@BOHn{y8G(Y$mxO3y z&!^HLH99wyI;HlrM<}I^;U~>mtWZXQP5{-;Op%mD)$09xHxw3Qb&i4hKf{z3Os&@NJexSb%HWMiS=JZEB>4+> z1bz0vm_3U{lV^LDzS|`!*s9e95xXt{!1XuY1ZXE{DYJAPTFC>5<^eGwB~n!+lxUpG zf`tu74MrUD;S#8|8$wl-Xi4k(19(bq@tH&-Y0UnUW?_&UD@BhXyGE=G-q$E9qD~U9 z=+*@KtSr_m#yKUG%v`^G+XIRjK#_2=0m5S+8!`I0$0Lt@J_Bzh73B$O`>X3qXd7`ETFbZ5D*uLBX)kwLrvR;Mgj1`G+;h9=zOLy=~TMZFI1R11O z7Iz8EHAYkf>5@d*0IRZy_wOeHLLj1U(tYO-{}KS+cFRqIG9>|2LhE*IF+t7Q`&xN# z8jKcS2B==195sthGTIXaJr$8ithCKq<8sz?SMu^QDysG_JtvtnT4ZX z!o-g#ro=D>D4}+piRhY8C!HqJLZeL)^`kQYD5X1ZzwM-VssHZAh7lh3_>=Gamr2qr znG)s96G~Y{#4`!4Y)&lM&-hd9h*$!5U}rEj(JvoLh%B0ty^gCogiyM*6{=SS*bqz2 zlTM_iX1GZxiF7#hu$gt!CQu|55kjTp_<;hDM1!HK7v@l&j+wBSH2m7L=vT+hKr>fz>|Z#)i#YtBoSEW0ZYKCNwOsl^DgI_s%i~J6F~+LYm_Nc>LpYFNGz?Olms^r~;G-8CB8H{Np0|x;@lrnc) zOHy=a1p$du15F7K3Bp)v4I{OxJYp=Gq6zh+i#kG3vc7mKXvl$zNGTyE>?YlR`}^no z<3QOzSY0=k(>fx4a-Etlgtw- zfOu{KYDx1eO@ztmmy<$hx<-+oF4QuH+9cE%A#+KGvDlc9XVWR7Q3^p6bqd9z9N|M_ z33zHYDV7*=)&#;#q=W)0lT;{|&&#@xkR{?{wN<>O=!tCBW3hK=rF+htB4FwIWF&AR zX(A)jLHHU|bP)lH(ATKFmWX8bzrrdh38*AgLM0GFqv@V2AUGERkpLXS!j}AU=kHC9#=n4$g3m(?VvuBS}5`-?YQ3J2AlJ1 zG{_RLCAd%2e?e(L7J;9dJP!)}Ac+7$$r4*ZDFJ$q(9#H0MKyt{Dubd5tJ*bhI}Rpg zW*W=rU|UIB_K znFYu(!)P(00BWMn8kcmF?)QK9Pt6Ly_pLvn1V~o5O_F76Mgzm7gH_gY2!~jE82|VX z5IX_@$O^_+yhH_@GWrRZL2X2!vn^a8a;~5>Q1M#RCR|!V$%|e)1ofkj6i^dFNr2Q+ za#}J*BB?SFfJ(MfbQd!PM1T|thzJpgblUhv@BiR~ufFhyK-QEGhe5Ztu+KW_fU_zf zc0L!Moy}A=5q1FCt`PzSFEJ!E+N>BESat|C*)^ig>13XP49w6x>PbPic9sKl2nK8x z;Y%q*6fpHA;-?7An#c)vBKIH&loAfP)Yp4^BV&ZK>1Izpfw5tPCosP7*khM==Xczg zGIP&-YN~|VQ4PIB!i7YfPY@)bCX|kpP!Ls&B4}_y58pXQF?SxZ25I8_Zc71|MA{|o z$f7KQsEPFdXYb9LB)N`sG5_4piHKZk=>=$@u@EFNAcn&k4vASPnQUabS7y2oBQu%l zSL#(}dKsB?A7)Itx*QCK!v!F*kk}gy^n&hMG9%7$*MpxE8Cl&R8enhWq_bF+SzX=8 z@QOUXeg1v1j<|?4puqiUGdnScC;Ltqwpo*4Hm#$|tU0NF%BopS8Pqli0d33eZ1zw8 z__NU!Pd|75_;mI3xsX%tbMB%sN|mN%jAZ5F{94V+EE8B@lX^udZ!X`xR{w%ht!#W; z=l^&aK$0@dT@l3sm(rG@ku7lT^wtrk&)a}9e=3taGU4%0%gD+qIwqxTsySuH$1_vY za0rM^Sj=bByTUB3Q-ARwsOpe32>E4l-P0(EOua&_Ls`HgTO%fQV3s#-sP}_u&dMld zi%(u_Z=e*}epf`X7&M46`ApFQTPQ`pGW|0O)l`0$ zEEFRHh%sK=UyOeEfBxy;h^^0gxe(1Z49ZM^35cr{5~^sFPf4xb>I4f+P4M4{iCD_n z1)f~_%l(%%du3VL3HAQ>0ijpSqbr(VQfg=otPQJFdBOk-P<9uI#Uh_#u@-zy98uP# zL*u36Fl4GzY9ix6F)|UwCVuDnXCCfpv@_aOgpbDl@Bj0^Xj-pR)At4hfx?W53u`dg zMv5!~5hXPNa$O56+{8sm%_m}Itd%R=J?B#NpuFR~!lS@NdnPFnjEN%Gefe5wj@kXV z3+3?0G>-R6q%ksMR$=Q?K?(p4t;nj`EQ=^$O#=wc+5qt0qWx^*ichYjv|i6e`auJW zSvEx#sCROZx+@Jh9o@JsSNS#zMxN^Y)Mr{=_?Cep5tye&igzH(*_=$8VInr9(!gZ)L$@F-nAOahCUBsxi=l~69xmUVxZ-;+ zf9qGjcrSMCdYzge{g8bxo*AsBiV#=}NRkMqiouE;Gh@6l3PN;ri%-OIx$4dS4P0~G z%#4H)Ml?#*Pme+%%I1rJ1vg7HnIbzf*39c>DtmQgS~`JVBsq~fscKSEMOG3ev!;;{ z5W5g(v)5jGd-?|1KWL7RhJz4>eh3Y(RyhW+Pzt1KNi8&-&9ZJ-6Z%xQR2ft|C}eN| zCs3JK2}zx^lnO0Rp)RF9mv&3hr63xzIVwAHL1}|0OCm%J8zIXs6D+*7o|>}XtQG_* zsn6iaEUgr3l+DD5DKsHQ4ozt1i+}is|L-9jK|4ERyNd7;8TUPukQn)BH3U}waEPPS zY1W9c^BGL8;L`d{%RY*z8t4(mC~+!Rh^Hs)txy|C*cg^n8Omfn-^yN8Ryj0~G1bD$ z-?z2&94k(rvM{Tf4yj`8XcGb}LeiS(#K|OqCCcSXPu}5+yw(ilq>mYvZ+A} zAhEo1|-7IWeX>pRO7ga?Pfi`8d z6UYs@&Sh;ghAf?7Rc0$AQq7Jt)SO8bu%-pGL1Bb;*8TLKe>3&Mn{OYR<#krD_DNG# zRP-s6HDVi(@F;GeI07&53a(U*4`0-Evu0Kr! z83OgadWg+spWS9n$0^;#Bt0iwU8y#$Qn_^6w7$sl*rm(vuIuPPKjmJ zQVLi4-0br4E-p4QtC7`Ty;G}~+_B7V)c^~DhUC**ga48M&^F*RA=oGNlzbqn5p`M3i&N zL|FoXEJkXhw2@+zcDeVPH$FJyif5l&-oAah7p3og1V&j405k|?-E6;&676M@10pkK z%4z{+LN;!Kd-oXL$K%R$h2j?9?lRgm@f>5xOe{o&A#+?X^GObsf0H+Sn?=FZOSDmm ze#GXe=A212Hb!J^gQk&LCru-J7cbqqadgHNz%hWmCaBtaWg<`|7WhtO&Ni|uRJjFW zE~{^9b$`qgYvYm^H)Ym9k1}0JR;uS!iRB7@mFZ@+VhrO#Se|`&U(un6cN22%Q|Mt7I_4X%JE# z6(BbPjUg0Qcm(#Af`GV46_!HZxds9g!=k{ayj+PAQdY9^=JM`}GcH9T;xhk4B_*#Y zWh#?tt_&CDI*i$I+Qv*ZB_mR`WJm@WN5mHMy+%01S@)NJ@%^{oKKlmQ*+Z~hAbd3T z+qXYR{qd}g$ET{9jG#usWtTVQ8r%v3g1ElxxDu`fE{rD=D#(KA@cte%1unqNDf0zt z8cPL=QdT4CYC(w;ehMVDoXrJdE1{YLQyu4~Wy^4^jVKR8VyK6c7|=$vO=u!57PG@A zp1g7G_8C{)KC;u3&$~9R)|xUg!#5wi>o;~X3s(Rc5s6S`UM7%DTwy$JTUa@vd@I~B z3qyALg3U?ozzV8;Jok^gB3ERP6Rc#lAzN1C%2lFTCV2!CZ0H5Z6l@?(DG@1)l2O|t zMuZTSdu?pGzy5E2@|!o_Ipd1|`G5Uie)iLUiIH=rG#F6$W;KCw< z+S+vn6=A9|%5R}^Z!nXv4Vip|J1(dC!Hrt%Y^cVlaJFm3ZmHRjN(qj_pk^`9hH`_sssaPj9jS235_;f)r&k9@C?m4U`R; zszZ7KsPv_GX6{e)ig1_xq&T**)1V5I!>d^B+8O_1g7C zU?N%%CIT;Rgq>b_dfw5dt79csX zyC;QGrUnF16GpmL%1#SN)DNRLrZE+`ESPGkZA28q=8h_NDQuL+@}VrlV3gO&Y|_9o zHFItnSf%%>nbdv~AP1(k}Ks`rz{~dV?G+v|kOL z2X%892F-&3lm;8w68x=^%}|mXj4SS?90VNoGp-Uj58OJN`05@Pt~D+D^4|6|ZytDL z4WSg8K}gs@Bq&*_zf)pxu2Um3kGNi0ij-W@e`St$l~A^uxWR13^I13F>$qFI_133< z(1EhEKfrc@@KM@)u})d{yCw)7ud=U*o%SY`(;gr}f!+lfSHhg2tE8wYQxIpR{%anIx8+JODF;Y>O>)`nUD*i7tlng+N|MO z!z31Cn9aH?S5AJ9D^zcZV9_>Yx>}nEVAdz!HY0CHN-dBBlQ4O~N+2oX!#1RHaQl_8 zBSNhVQ#VyI%4(qJ?@7HD1<28;_Y|t(hPLFbtFk|1J=cuRW+N0Lexs2CSpjgTLj;R^yXe6B`OU)GAl8U zD=#0&QZ5ml>)_5??wi>vS5MZHlCU~CYQ%VnnjIvIr zMhAOA0!y&A>t+`(-~Rjy?}|QkWJmpw8j-9D0taX^Uyu}W+E(vulL$6F^C~;cg^aX_ z7mp%XN!9zP!iB-r`I4M6#(80UBI{*hrJgRvyOA7VbC_fhyquX zBNJJv2+K^KYGLEcRcs^e(~y-xg>a;@G<&vARW{FqpL1tBd83nr3CM$`QzZ7;Qr5r@ zpeX1;LD^AbF5p8zfeaX_dO79cYUuUiVQd;9*1biyymlZ1ygFG8jfeyf{vfr~8xc7LLCO>xcD`(p+Doq^!;x;H5ipZy15pawd8God zM#?xjRdE&(2O?Qk(~=*MFvYN$)TZo^X=;R|-daNe@)%bxd?vDN41$>mm`EZ_>F|8h z%|g>im>+!b?v3B?ik&@B+Xcc$Y(MzZOV>ZU?yG4*;HhX`*dp>pu3F`|7Fyk5szN(f zI3S%yaxC(+3S<|w0#)kEIz)8BE7UMaP{4+)MwZJ`gaImb&A^Ymz&5D!Q8^`5E(;r_ zeyxeN+4+Mgfx9*;w^y&8eyJIbj0Ek45nZ*)yS4AlN_^>sn=58bQKT- zY0$uQ?yxaf8{7H8`Ct6%qu=j`E1%p>`L+P8N?>7lWC{VRwKjnOiVch?gi`4yE$|ku zg-E3$Gk`*=0!vLM?5ZZErL0DU@v90G)@ffk*`1dssV22muWHr>Le zhGCTwyYhlk!JrjXs0BgM=>%yJ7@06JnTZtH<1#UId^9M8GJqt|kS(d5tTd^$0a7(O zJa95BXYrbf#*KlyO3hLIj#MdjnS0LIfEFp|(NS@^UU+Cqd9OeE#ycu3tO5DsZQzJOfTn zSHmnwpDp+t#!7heDdtEiw?Q^i=>&T7&1X?QE#t{5h}E7a)d{GUC4_NBq|AGYE3&4f z4Vy3}Ejk!Q$U@BtR-BtgvjUbXUF6V5SMR!zzJ zK_gou-`BoxJzOGS+XuI9 zAD^D2dBmU;1geyKjSZAGqtKL%nS^0PL6EYqAX(!r)0zs5Ez=F{{Pe2*&Z!!{qncn{ zQ!!Ot^~SI^P@l`}In>(GZ#e-aGt)YB_vUjl4#ZXUX;|qKPtG!oLpwV-_r@Dn?!^^5 zdvLZ3gpb~UMU<1%Aw{RY0Fqi1Oe;Tsn}Ii*bN;@qbg~>RUM#A*j@H8mMXZTF~kFL7AahP09M9jzEYQ)C9x^G4OmIq>-#? zxmbSkRRG~PZ?Vy_xU{ZWR*MlsDmxp_-Br))a%qu$Ke{YYP}wgW8^~L(Ky?MfQr2u< z{F!SbG-0#;O;yLh33|L1^rZ+vQK1rcl?ki6-9;OUL0!ip6omKoq6q^QyMqruyw@m5 zL^qF^=vcG0fl<45suo~sRPmp+v_XMKG04%jJ|YD+a4Fx8ADzP>g@Ju?=B}`m)m3(z zP^YhxdfL-378^69(A*pV03ZNKL_t(5;j(t&j79G45C9@mM-EfhNsJhhJ#nEk#(W<4 zFFgH=Uw-%%ZVOqq?dfWj_LfafN-zl+dTj!khi9VD0FIwxGBYXAS@_V-C#IDpoT58o%XCT1|xkSr@DwUiBJ-r?}33_MZ8Z>z{rhZgyu6&31wCv9Nxa86EY#?zghe7MNH(=QRSQq(KNW*@~kA z#$#9|Q?A4!6=hnwe-nCQEqc5Tx~M`&@VcD!wW>5@ds)5NsIa?440aR%~ zRSgwJ@F!cG0S(*<$wTjjt>_Zdfk5{^+ z)xtnKR`w%a!wba9o?054UQkvK)y{dLO0it{(X1|xny?Mo0-I*_RZC|rcTkLr(I+KS zb8b#DnsvfLvsq|c?&gg!s9An^W&KrM@%*!k^}0Vk8V(Lx4|Sozu*yvU3vnpAf-Ejc zPnt{1#34&n2gAD;G?FUh>M`H1m?+J=cA&A>f4RJUs8YELQ}RJzRx=ado>p7`#kHSji1H(O!%pw%joTrrmc0d9w=JbQw$gu$0t=&Ny>q%2op&m#;#4JA z3p7KRf}ooTK(j8Ok(7snz4qMGFJAlfo^mSj-|oDXB!HwK52Tre!iq zgQi>%E=j2$EQUfYQpnTbrTX+#+9Jd)YL{;UZiv-!uL+LvDV&K{2K0^wt1N#|XAx?1U?6|l7})D-dHZWJhFrU8m!1fxt5a3XyFf}gD+lU( z4FSXyVrl3V&N(x{R)ad8(=jrkFoZdoYAK$q5)XmQ;N=|v`9KE0IZc`;5P{1MPZ=}2 zPhco;Dxx}6b_6D=tyaE(fwqM(x_L0O#XM3Q)bjpbd;a+!T)px&_XIvalJood=y=_B z(VHJRTek=)YgvS662Ukmb^!CLcW@IhB1@?}D1+y^YANCp735qHO@uEUGE-y<7(GKH zPoa5#f~%${QCZwn%7cXf%M=6>xSK}~=$g7~=avr?|bR_{6BFAvE4cR%hi=y5-RdH}OnFtV8Y={z9Ww?nYF5ssM8;;g~BgZaB3;~p;e3+>iXICn^W zzgDGr7o0I%BK0W?hzjY+2>x`ezpV%7kG4X&QZ?#a=)535*{40FIQBGxOkH84QiiIN zqga6oW?u;qE_`D?F%n=sXw!m0O~V2Lz=9@?gUQl=p=M;z3x-n zMQ{A(Y_mB#gE}gjgFu=sNZFq32hGlqS6s2d$GW^9ikkCCUTq;1oUJd*OPxBGW-@7Q zoSHA50w!f?+yt~JoMT1YypFJ`72MaSLZ>HlP`4?0$xjxX zEUB9+01EoXNQ~Ai4FL>vGnT+@7u0OAXsHPR?d>&}zWbL~KH4=!A0yiZ!pF;Q-r~c3 zU9EdFn$3bKW!0v^Fk~Win4oiIn<~ScJX5s@=w#OeA~l~9L8(>=UOKfcsb)XrbJoBv z8|1~Jrc!FE%b7YTP6P%Tw4gGQ)0JgwT4taTf)Ep8$4$h=!?x?>tq;FW`|FIIt{b6~ zl(p>wK%|sa+s28>6{xz1b=Vo0Vkp&cU~@Le5iCkB#)ks*Cs-3lhH=d~2R30NE=of~ z%Goq$?UN4$N#N*wQ!BcUgHMT++J-^YHY`HSA`Rw?Mp*Zj^LIbK4|hef`T4_i58Jx-N1nv#wpv&|G}!^`F0c57)Z0hiAJ$ z_}JO$y1o2lxOKb=K|%l-4TA^F(y?rK!>C@5lE`tysG4$a$OJ5 zz$!49R#hSg$e1t@Q`Z!k*FsF{6(LL*05uIafukTq#K^G?ZG&f@TqxUbKkn|AD-?_6 zY`A^2I@q80!w`hikW*3-Wc+X^$H01W0J4fgiB7<7K{)I0BgIitco+Nz%& zo*O>-=;+%ooV$J011_^mAr=WKRm+2tSx#2;m|V6xsT!3j1JQ`7_Foc%a#qcS3oSA= zLLlQhWl!0fK!xeTtceIr!XUyh6rHZDCPFZ3I{~9;l_ ztl4rl)2x|Pv*uhyT3uE&RH7*dnimiqh{+fvg0^AbjV`g>kE^{d#5wwv-xM{cv5~IY3CW{VIB($WW@2b zPDidnps#ZVu*I`!ZW}5?N>z(e~GR7`Tjxw z$(7@0pE*cbL&G+x8imLb3WUkqm8RY__P#E~K>nMp1Uf~y(X#=cH)~cHO}Q(ykXJa} zIh+xm0rG4>3-u_Bd~G8(BEnHvA~-||I5=Fik>tX6-`PdM$I^Cz@G-R;xA`x=cj4o! z*XHxi38sZ94H_bc0L|*?08i?x@^~(+p8^+Zmx5BYCL*Om5y?df1R=l| z4?=_lv;h(T3G;ba&ckeZ@cP?-&|L6~?DlE<(zlv7fBV^U&z#FS$0l%2WxWj~Rl?UF zXfC@DexGQiUn%SGR`5hQl|{fxr{YT?M4-TE0$d8pl$c${7EEBG7|=uxftewKAS{8K zhGQcf`@tBdFAgP^=sJK@3X_@jn#2}>f++_Tm7&e`c+N<82z9* z`$~IRcy{qp0V&a-P8O@ee10Ewlm|WFDD+~ZktF^Y#iHyxpeqAVxHe z1V)T(M6-oF{lqzD`{g?i77P9--^TkNeA03}Sj5wnu20s(phnd9+9x%ll>E3SFKS`{ z8D*lRL}npyy<(_`OQmwI8L1izTo~C4h3xY~qns_q0umHPSJ;P_v$_G^=GLXI)E4iQrV)iIB3F zcW`btD$8?3M2u2uJ5Nwi=ryO7uImSb`3OxIL0s?wF1Zjo>7pdH*hp5r{PbZ@>nEQ1 zv!DO${Rirb?_559=eM7q-O$kwYNB{j1=gHIL@)DJuR z18r9kKJK>aXNTwdPp+PP>$$@|S=$MvEP>~ZNUh!+6CnW%LR~%dB{R4(Hx(XJs;ahB zq9CdoEinV2K55R@G@weNU3SZu+NRKl&Kho8=ExT>E}uNVWZ_@F{lICWuHU4ji}UC6 zl`BW*&drE<*2>XoYP--z1c3w;&0d$OV?f}uA7=PwTOm^$NkyE8S}BAw_wu9A^&nGH zVG04DLKP;Az?4C=nY5iWL7Ko4rJcz$7njn|!TINY{>B3r)46g@Uw-L{Yd3G6o(wF! zST=1yQsW>^!y&RT6{HIx1aI0o5vx;`!l`IB156t^i4a01Wm6i5XKBzNU?|MsKnVw98)4rfF*BqgF4 z5d;8W=5tNgu`IWTfD7YVxn7J49tO+S1QstCorfY55ygQ1M1w#WToVESAgF0K3lcGJ zBgA6c%x2-)r}k#E@a6}*O^L_dc7gC4U?;2YyU%xTy?ga=f5A-cEV{g$1a1OiWam|h zPVY5-s+dr!MZr#r~V`-Zzxcm)iSR^)LSR zmFu5H~mZ?wjg48Z!MWvZDXIDz zK&9vRpklzR4a5Lx*MJ#_a^d`P-gUvb2aqY zNxJ)9eaEEA2S5Z_Z5Ya8ATt0sb*B$fnaPxLHph$*;No|vy-*{HjWkUl29xd0cu;DW z-Qld=Kb);o|N1-pNL=wh{p8@EUVV$Q1(yB&?(}4R^Ye9NklA`rQv(n{>p@YO(6X8- zrKDg0B!S%tj*FqXFzRyfP8|mZF@cKCQ9F}v-gttrw~Xs-EPUzQ9-D!OQ z6+e7YfBEZAW(|{tC^$M=rM1pm9!T+Rs$2^hx*Trgs&B4;%8 z>Kv*Nr>HPtWU{6UO&cKG1cbnuSOR_L^0^!R>fMhY$jE$W55jhV@Ec}-`Ev8?w?AkR zSmf|vwmMy3zq!(+P2kf$_k%K{35dc&wjtYTubOQbEQSIcup(Rl$Bd@zqc7K6a$;+A zEvIZDaN7kAtZA5aJexO0!IFOK*~6#4_jmut|NfsJttF@vhfBc94 zZGCFXF7#`Qup2klhvzyrU9D0-sECV&AtmkmlE#^nl!A!Bf}BmW=DL_qWaVBd@HDs( z$7~Tp8;yubm-8?fVjC}39)Zgk{j(K9x$vP_#g72qOCCeZ(3XLdf05d~L_ZLB8vp;Xa za_PeIR^ng0{$Rl%U&+4x%+Y)A-P)T+%@PCOzIDok*haRz9`d?ZmjoiCKB&IYu-__FRF5+b(isGHn_o zV~+9Mx#e;`Bg#L2>oL+2`reED(fe0Uj??*r?)I&La)!}-(HdDwc}NN~Ct@82OMPaT zFuF#Dq$jJ)fmxtxAQ}eebBC$5o#d<#i9tBBnFUxola$dey9)=4rsb|X_~|cqY7*Z( z+XcdJu>JL);umjzB1DZuBZBF*8>@?looj>-L-v(tKhXe6*@j-pEM@DHf)E4GW}-tS3JGc}KW7e#eO(N%{p+VE|h4U8$sZaTE+5YU&H2?0& zF6@7{Ix$miqnw^t7o16xCGaq0-!gRCm42O7EoWQzs%jz}8;K1&T9O&rNQrXFv1rxn ztmXNv4Y6xyP1`h@`(OR;(e#AB)V}@v$-i7`SV~YE64HIXYUMtd)gh4D0n^ zX1@BSN5y`4MVfBjc8iYMw%u>#C|>y2*X{>b=0mr?`%(L^zkV;R zDJ5MlT(gy!N3sk(^ZR=BjrTq|Ia-mKKp5gQyg6%hE{P)CX(^en688N-Y%zw#Vm6<5^G326F<;mV zr^f&G>u*L@w6ia@T_F79w4eNdfA#i9Y8ck)LcLAH!Ysl>l(Xin#LO%)hQq^UU|tWy z^G_^~`{7?+|KpKK`|}@Oj;9}Ay>V+bq?4nys=6=&8KtD=a2W|r)3j|nYghzb3<^5e zh0pr@`ZuKhyBB-$+x?~G-uqXt9iJ#DOOVxSos&^5f+R=`jj*(B=o-$NB*=xmZq;Yq z|IWYu^vy?o1^3N<{HK^V&2K;X+-YZS-8wCTCYo7IYyZ9)TtE8pGsDsQPcN5bl(RBXvV1)e?|tWA|LdHJ~wxYkoFd=)({^b!}!TqrphL;C}5=#85;zOIuE;y+9{b(Y z?t9t32Jzv*6{$&q= zn>rYqtK9^^Ge@7D35PTZhYSm(A9auM+Qc1paQ#wtG2(hNkex{aw(O2>!SwMoMNom> zzVJ;FSoipcFRA~|ntj2ui5GVf@sGrIf$*Dce-{3BZODeaiGP@OLAMS*JA2rj`4QN7 z-kEQhvv*BN8|a(#Zx8q4zM4JTznqMfNDW4$wf{Lu1#sr_&w9gtPdGF#Rgra^-fJIU zh4BkFF7_rmhCsvQ9>5nxK`OV$*#gKP+_h!OWXBgD>jJTVwFo8MS^wQzIJB)VXTP%v zheq1H@|f;Z?(AM{7YM(p_Okr#U`PZtsGs{|5AaNsyG!k}9R(-VAtnzt&C)VN)Chft ze*Vy|@gD7&NeI;HfvPQWHsDX~ZpGo*{9zgkCk3K5(2u&`J@||J3U+w?iDW#E04J9} z%>d2@0K4mfzj^A?gkR_rhMhis;qZ%FpxFBICE;+|M47Y_HeYP=r$%JmD~~DT#Lj-d z?E>L9&%Pi2X04pa8-S$%8bct}PT&{4W$*HBJ9GM5p;)YO(PJUV1S(`L^4s|3!@J-w zwrBd6Q*DH94+6)dA9lCDc(&_RU9x@HO1XrbKCp}XYPP&~NeOi%eCAHL zhhpfg2hJo>Uy>g%^z`D52XS3r)xMw#M18Wkc6^~*&dd@7j}@U)&ndiulzmt*`QTfeFxxuX!=3W3;EgcuX1Go6EK z8z*cR#G{_)8Ru-x4vq5cl}FFUzO#F@T_F6%*!SdbdP6eKj)=J<1l}3{rnVgew@RPM zH|qP`rb9+^;nq$1PsUIoi^%Ws>ksy_?`BW0zvn%`S`cqSpxtrw+nou)*{9>z68yFf zzUmpL9z832JEE_J%PukX~E7|9~B^vE{WV zbess%xDHWI{)sDWQz>FB^a!}?xxdMZ>gVa$c>2_)->(nqPHH}V;(^Q4k9N0q=vD|s zdCOpW{A)3&001BWNklcI3Z5Ie1cl%TMt5ux{W`8qVO=fW>@xRM?KY4%K^z^sw)4x95#6p`^LN@jWx2i)X z6_}8=Nbkx6-$1{-eyL^yxT6NTOE@Id?@R|n8=E?0k_nWrlm75D7FJi>kr@;`(T#@^ z3m2OxNM_T;@N)j2agNn~p>2Z2*`t5UB{pdc6dHnZy&iHw8$VPBZsG)!GU@us2ObN* zs2z&UQ`E!}Mz8?uKmrpG$aoBtn=FE+4U&589uc8L*|0VYTMd$F%k*xsQ0Kcg>Ems? zK=@eOOZ-=B<780s8fX&$h{m(*%q(Ox6S-?)SdaN>_HX0iH&%fzOKOt>aZ(Q%NGAb6 z18GG5AUwcW_|*EPWKc(k)^n|1?Bv9+SB{b>P|;MSyJQJl@P~;X#xO9+6V6=zmP6{9 zSki(9>FVOj1MKF^<*HF18%F zr0pbND`}|TVHlJ44>A_6Up16=C?;=)ab<850+nD3rT`Ndqm+P*ZHLradA!@p)mzyt z(h?D&M%geJPNwgIv;ERBknUpP<8Qk_`1sn3{8xRAf@;%tXsv!QzKO93f!Ndq^;^ZZ za(T8f?F+6e_U@BHi9kLB1}LG z^WX<2u319$#+g?6)>YGZ;X0`fm9iljjtmt<#%E*U^yw}ZKE5WGFTeDtU&GGsVlU#A z-o_n?akjB_=+{c8jza)|n85yCFNfioj}j=#PmlR9wt@!T?YtbJ7L%dc=1)BDJb_#;$)vi`5O({KiLH~}7x4Ycvx z+zzni+e+9Q=BLf^ee}cLwe!hjjDpjG7}M^b`(g9J#0)T)srZ0hs}k6J6n7OR3U=32 zUtqi|N*A_%OqVV0Of)<&%5kI1`>fowepQJW?B4 zfr+XN@0mJ?fUUoXF&a*%M;kjE1a0ffv@o=BQgomPM{*x9^iQr{taHI}Np1u~!p4`6 zGlihnJEH@@^(mkIu@dC5T?JwrdvRwhtaYKC@xH@+%I%zUAW1I##?8*&uBz)9Bp|Y zl>9sjPD-;)6jbuI0oxv1%NB)1Or(TB@en9rA$SQWfS?A#8vNvJAl$q~>U*vR!tt?z z$hqnxQD1yeOTVq*1qi!X_!!zQ5I$b^B7Rh(AlJFzG`ZX~MYsD_n+FW?cXREKjj_;S z6JytOQ%cg-`;`2oyAyA7rd7HLf0OCs7!D6~??^uXLtJs`^t-7#L8pb__<7Uqt!>`z zz|W=O8`q z3sNi+mCx#9Fo4QtS-nuQGuJ&j zX=`@s1>E`%dzTF=M1prE3^F6*USl4uMXp;#H1-oMwMu3#@fLGld!Rr z&M>&tf3?W-F6gFvGF}LX0H$%JNX`6%%`y=alq}l_l^s(-CNdqPBZx3#W3^K1Mg~$PBT}<+-V@3m;@I-U=m(J1#KO+{3N?5D&V;A zK0P<;Nlp9GhFT@FFT?r4UYneyFR(QW3D^-4L| zX_F3kH&D&g@5vHgY|}9{CCHUFKehfkx5d`J;3jr?J2Wp~4Xh$!N(kgl*ek(r+6Z-r z5Y;vcX!DNnq$r!IS|SBOt<-?I{+MpPI`%w}i9ELif#`&YOv*hmeG363w_iQkdu9H$ zT(PtJY`Z}CxY)`#RVk&7gu)%RL5NZffdx5G-pxE|nR;C0@!&6U#SAq5hup>}$bg!i zsU)`wz_Ph&DH6Pea`j{upPRECg z5s`>^@&n}s`+l66!PFE6kP?xSa*2i59Q7bFln4zwJt*#G?8t%I+I zA)0@7kSmSqbS`*DEr?qBfToi_;yNoWpDPxoKHW_8%9;e5s;OCqWim2_L3Q#ArqVU2 zono7|9gK*KK}4h_CQSYVB~K!7yduL>`760%^=h6rBFB%?5naGq)-WPs*nu#Bkk3aU z1Ys5+)TecBz`=c0|8X@lE9GD|%cN`swM>+){<3YWM`D}7EpMEozFBe%kKr`U7|Nqv zcl2?wT_Aic>^t-qYolzGJqj8O<0z=u1jAPz`$;yQaJBnW{wPdZW5tXVW`(59lxT7q znHm`6Q4pKD=WJ87{6lA+*x5fRJyOFHtEWHhKE8KXtZEe0?I>u5u@Iy!?CTZ)rlR0$ zU$o48gqe8~1wC#lnVD+&r*-V+DG?iKseLf^LhtMxk6FTG7kl&jvQjvJ2nl@n`QFWg z+xO^)z0dY~;~E7wR+A*>IlXgTWKsgcXMs{89|2(Dz$F;)reZVG+6jbZb-n~bMk;0A z#%HzIF(QJYxL`tZWPVeUk`i&P7)R)l8WM%ATkp&4^wj|y9?|h%qwMA2oVA68f)&~T zWlIzs5itRiKnP-%$cW&uRSwpg*eIK3wFE*Yg8F|p(_Nw<*IWrD6;L995upLurY^iA zh~oCEtG!)=^f9nqAbj-p68+#rQFH$)D7dWxH%+yRrdx5ZhC__Z zq}X1vQzEkezr8Q*lA}nrG&7H^(gHj{Vp#fh1Mke4IdkTt{>J=u{e=g;ur#2iS+rG# zo6QHe%{?MZ1&yji%T0MoSy@?G8I}=#?Ot0PFMi48b`+8x1KYs z3|PK8@P}6_oO$x_8Np#we}jsGw~^0%UW_LNtyZY%qEwI$q(w2!Aq&wN(ShiIv>+NY z6A)mLDqKZY#)?dgWQ>0mfkco!d+KE|mLYBFQW5~K&eEimfyH`Ik zro9ZCKzQ@^T(HS5Hau+0z|?Y%kW3nNA*=ut#D!?_G>GL!yrM4@A7P8hMFgdXK1nP6 z9wQuW$Yn;h1fU8$yV_~?$7g?dA|4Guo)#U7sKZ}Cpalo1WVFHFg2hmu44+QYg~Wr^b~B--r{R&X@X}Mv>q6=UYF&{o+Y0x4(VUH(AW? zZTUhVt5HPAEZO@CtZ=wkrD!R%6gm(tC4jJ<7bwC4!dzJ@^U6}Itg4!_e*x54qu2(S zS__3lc%WHmEiOU=;RYLug-Jh01}tAm{cyj6sXv*D`!x-YfeOfH=v+|9$~!eXSRkrn z6aonsq=o1}bXMrBp(D}3Qihzt%NbZT+W>%NEmUN`A7((y$Vq#r){ z!?QNlIHv}EZ@>WOJP^lxlcmA7_)%G?ELavQg$lJh#tRXEL72HpExaB95mse_To{E= z*EP`zA}IT1vs=$tDap3C!e#>8`TmV3@BDm;D{g)BMg^_R3=~8gD5HA@<%V}VFQP@# z%A~LqIutrAbXKSV;gSVXLTc49RVwj9wIE(pZb~2%E(DdabqvJlQgLlsyf(d zOQXenfpw`s$i@_dgVVq5XEwk$a;u*jgE z7+9A)mYPQN_fT5#4s|2GGX8t*ltTgmH56@y}x&UC?ijahbET14uAdIYgSb#uM zMA1GtD>eh;&jJLzAlwFg3N-{$KXoQ4ykVO_c$2mYW(c&kPcSViebp#fs>El0K&y-K zw9i4K+|sbnCTKz1Nda3WpNJqz5 zPQ4#qY^OLh3*P$2?Pu@q_m$uJ=57@nbWwJpIAno-u1T(+RfHtNzm^wN6g-q$4GR$q zSz?TFHJ`Ik6{(C&SO}Sr1gVW%Xqy@KKvI(qnJD4jJFJhR(@=upb7vfN(E?WNqYdKuCdSnCUO9Ns?XS5WmnS7r@bVbKzL*JDgWziDz0_;lA+(1#Q5NnL#7W=yEjoe1!TM$`^iy(-0Q`m7? zjKe^?zIgobDQ)OrZFKN1a`EEU@=Iur`us^ zOaXTHJMl7YW2+DNzP^nVt|tJXcEzG5&0_x3R=Nq|8mS|KImHMOpz5Oj6$|NP$wez= zfGgLg1V-*q5HN)3t^~+;sXbXdlnWyr5oJd)6<~l{kItUm8#iP)|K@h>Q7{2vmnii! zB#XEHK$D2I(;k`;B9u@z9*->e4DPn8T&8(pH-l? zEJVNkIc&tn#Ks~7O-q$NO{-=Ii(dULNdgPed0CoF3Z7p~udc7=G;`c-G!YT z+pVeNSv}{mUYGAx=7XF8yG-h%WDB-?^ui|I{z|@|S3)vnK9>6cn!*^5*^? z1?^n6fveyTG(WTidQ2ZJ<@U1NrE+dpPwGF4<3%e$(n2KAv98p=Tikw9Vz4L#a$B#6 z;dl}7`-i{5o-NaUg-sy589VaOFz0K8Y#%(MLwXxWCyFB3N>BhJGf7 zzYx1N0t(1lFIcL(LSoFcA4&H%bFMZK@{@=dM7G01>6{}Vn=I_(hfmULsHu3qpiq~R z)Bi#xh#%Nk?R-YFc;mk%QxSmq$b5w62dj$_*|2}~^e1-d>IfjlV-ee!LO_$6Qh;d- zgzZhwp2C~4DUIHYRU=6axU>pShc~9@<AFggSAaW+m^DtO53^}PXN;nlSV3-@PI*Tzv_MP`2JJzMIQx3v`-*< z`XxXvFi6_cf}OwOD8%~ZxfU!UvdYSp8!rUJwH{Zgm1~u?a;@AN$b^9fvLE6QUn~-D z;(%Uc4onvT1~`0Ij`yQx^6c;DH6&#{C>BRS>p^JW@0^479f49@Jg*}z|$apBkBDL1%%qwZhXl1@&zG%3}d=y?G29bMk<;9^W z0+)pX)`u&ps7MIp7RZz2ioL_0cAYkX@CNLY_0y*UtiYpt{0OG?W%rWs0-C)4X=`iJ z$b+c+Avs*>z zf|1*f54QV}1E2HYIqExS?~Xl_z|kR@HEW$wQeV0MkozIyy87$Ll3tAT>3e;QAZY@&?k{2tkK5Fk z6`x}z000t!g2Dh`K2y z4F|JRCAlKa(PmkZFDkVDLL?Bvg|SMjj^XFEUIZLUjttrbtDu-t1HBV4?_3-|@P_913VC5Fae;sjz8PMI+E)HMHuGjc5=f2jWF_ixJilqDBX89P2`~0E16; z;l>4}q2LAcvC7IVEC6Ot3444HvU5T;k?tVU{jOFB0oyoE`=O7Y_Fwz?;m_17gz5?c zF49SoJActVps@l(fTt)(d}Jg9s$7T<03=w=o7GXU@^j`3;Wmh=1q2n87qX;OIP91m zlmF1QY6L)$0&))WJfGICe9v^%4cG+28?XviAQQT%Px0#b4mcI^jtWVui0&S%F=`b- z5d=m75~K=bGxHI#N(=S5iZtD4wdul55@bmR(yeXV^{vl&86I}P7zmmYL;aQ)jTVEg zSm=>KI(nVn+=^MyH_64ofLNV%0|loEHkf@-46L5dfThy{t-_O>xw8l$IUFD+lZAq*1XPobN4V zOMk7r#*lU_SXXW+s>%IcPi?9wKipxS>(vP3RjiD6bl6+4U!6JG6rmKJ6M?LV*o*FGz^A#@27Vz zA~$K%NlXuP_GA1ILkmvGXnaH%1d*|gMPXj8Mil|565{GR*@HlpwF);ZTpJd0tx-fH z1N#xvie;brL;#SU5b)sX)i^fm?9@{tVTW$DA*un2A9_&A6gGqsnD-fG7Dix{irgkg z>mNcu5wZw8I3+Cs{N0y`U!rDk- zaso(qMi1{jhmrQ_+aMYt$>)vROcUOSO(48(`_u7{&vcrMK$LD04&_bXiMWjUJK74m8Al+$jY+nPBTLtsnJ46NZ<=>N+m+v2k4|i*AFv% zf^FU>dG)WsGHe|e6bwe_8~gwy0P#Pj1vBki7J#-tP-Scrw1Gso5dvs?^Xj&93jfOg zR3`QM!i}*)WBHfeaYx7bHuJ(1$|Id6whxt&h?mOQVBLCiQAY*7cOR$$jmWxrhOYBp?gd001BW zNkl7uAx444GUz?He7VCp5{>eSSY#WC!h0K5Z)qOR?$HatNGh9z8Lp=O%Fi}r)sydH1)|zeXk0K! zqbyy+WnWhupa|gsKPGpAmXrz<4{#zP+EZDly>y#Ec-uJOUEmJpnw4V0+FG#DN5Qe zk((D?ANEC1iEu85Z>2>nLSVDK+Z<$RJEw+zDmpM4gs>XjbeCv6!oaD&p3|Q7%^SYh zaYu%_8|23=w+eC82?PAMyrpFM`!nS8YRb31MeLvz%w3@dt6HAW2u%gHgtPCBEG*K> zim6I!V6l}tV4kHivl78397G>Q6jJ%G^cp}u#Ri3N2Mbd!S)eC~_FIV&QY#?Z!9O&? zIW`4^hzkJ_P-&MiFp2<^RG}(RQv-WQz7{D(4uNGAO(s|cX`TZSI&p@*@gzx{Pl4a_ zovG$)+RfMm!t1s!&8Ge1hE%rkT};4J*2-9oNLsSftFaP(N7MEiT1%Y5 zf(R5+cZu>P5sp3ttZZW|b#rYL zkOYJ7*gf=-?ptI39y#gGCSyRH4u9Hp+62PuHqHU0mq)!13ej|C*9apwU4P)HESB84yK;1O-6^S?eS1Z$e5;wFNI- z?$#C6P$3buw5Sbf!cidYR*>9fmC}UPoQFZI;zjf~b6t#g(Ah>r4*MU#Y*vD#U=31@A($bzS;9)_u4%>v-ixLx#vvaa+Z|( zW|+avH!JOvHjI_W#x+y#(M_yh_Jq~-(F^_ z!5sO6CeYznyj6P8!o(ne=J&5f~$vq@-{m96I&Fy%=yS&CdGV-s)9tE|VV!xzh@)d`@*gzEO zCwFFR4Tsr~GL@Yl@h8&VwmLP*ssy2ELRiQUd2|2)Kc@$i4C+|NG)1VPK0!-uMbRh2 zRul(sQSIR2-XUZ;`Y9y|d8r(T4HNxxFHkk$iWZr|KI>EtpR*|mFZIugAEWfJMPXmW zh0z;wR$v%c>_DvJSB3LQPk55YMP7(f%#Rn#f7FaB3Q6?!yu>LU<#*dwlIK+btR>Ng z^9RTO?0&M|CGYYNX=yRepA5p?StSys89~@bV|Z6)>#(o1i=R@H`$+32X$JdiQdU1H z8$Mgk=oKj#u5#X2>3&(op-%6z{%g!uwp-L~LduwcV?F4VPIFW&@>A{w%Ra5(tr>sY zV51HV9gWR)ATca>XuB7cu~d??Kc-eaicbN|#(a)Kd?+bCYf3pN%TZ(DKu-AY%!~We zSN@hj(45`p4WczG4~NU_z7dCtofB8rE9r{igT$j8%W1HL1LjBaBY6}7a}Y8}e(4-@ zCrhY^nw|?HO$c@n8d;J@^hFxdl>jZ+@gNneu+tv2=}jfq6TRl97A@&+vj`5jN}Ue1 z|7Ax6tXq6OzshGpVOR*jzoRj^mGSH*7w9a(nSH@Syx>gt4DZG`d-*ys*~GDi zI`FBP$0_(_YUl9}TEa=m60&mrbNzz0v->FH>JhOJh+s`Um?_dcH}uSL3oE$+lxk^n zE6%A-4MbNJtV!*rK3dMK=jD?{jVo<1f(w}8+Uuc7OU#HGORr6U9S6#;R@%TVq_1;_ zTUPW$kkrLShJKldoMO)4@xbo1TK&Y#79!`4K4kEjKi2j<3k2%`W*m(e;4Sz|u-RIdQ_!=qq(+fEPLcF+B)iIKl+-<~W8 zDTmc(60uJ5@aF3yDyV)EY2MCMH^>}*ZlvX)MhQHMEGVCK^>3P-!)F--jkyFP%0Vuu z+4jpJT%-kHm6NyqK#B+zUnlIZt_%sniyV%x8?u-dl}s?vX%I`zoXi_GIf|LMh^O_N#`hR2mpOt>_do+Qlf!w+i7F#g zo6xlGXH}uz`p@|;83Tz1o}Y3N{LExFH45><^YjVa*>~A28J?Un)xCO z1(^>$X7~K02_e|k%GVei0#mZC56&Vr6p}VXQuC2B3h1fqcIbqh$jyUNorIMpt^dI! z(X5|#{cEN0!LFInJweLln-gM8v|%kRmE`9Xi%OkwgM+Vy1oCG8__;?q3N2r7P{Mh$ zwUf&^RNut&60-O7`BI5C_xLb{NykuE8iEhzio_I)LSuH(sPwXfV2j^T9_@ zdD>Fm;Wd9z1V#kh0p640Dv}%X4x>&&4r&kHlfSF}%dlHiM{|8!t}lDT%Ypi_Y1t0K zM0(KqyzUs6W$;~_y6ggD0TZ`|1!X5g||4LJt z2wEazBg?a;2>orY>!DGMKoho|6U77{h`KTaFGn#|{a^tyX3{8{?RMrm+vBq0i{8*o#8z?RE?JU1iZ=jD zV?ymyqf;SPp_1aYOrbMPf6T}6d@%8>aPsBDK%C3bG{pu{o&0?vWxG7bgYctXCUq*= ztrMcDD5k%ET2Qov9HrHXuWvIYn+<-33m(2@_$>}0w)* z(|SGfs8(kRQm1-M^O{0a%olc}@&41ICbT95RrM;_+-o+D?lv7O%2TlwtY-S2>Pn_bTq$A7b>>*>B0TLsw7q( zw)(1o+-ZnUp|f!RK@?vhulqTP6{Xf7k1#sK|lcv2W5CXvbT zm0&bktyZ#}zLjG$%7Gony~k}~*%Rfsk!9tST7vGQm_LUmtO2W4degbW>A%`tPY4o_ z|MCBN!|B~>k2cannH}T0pAia|uDL$VL_*=Vh+y`^v|D$mi+k9&)PT+xE$XaLEqZRI z4M-|$4#k*1;?*R2RJ#1gcRjMcI0xH~fooym1|2&X{`o)s(^)LuIec-|Iikin$htap zMH4-6I(A^(}oQX0tm}^mm$`Qc4TWy3MM%AwBv0)Z0F8e^}SYR?F?bMWZg1| z;Pa${OzOSy3in{k1{y=WWN1~)<*`|S2{o9v#b@)tjGxo18?S`~-Ap>_59Ydb0vA@S zUNV-BQHFe432m?chi~%gaJJA3(+){7=R4m*!KgDUm~_NK#$cEZUYaw{h{8UVkJ6REB-jRb51@_#Cz_wT*iz6Kpx;Nw6sf z%gJiFMG>7Wq}2dI`x-vo;}_){_?#fryW^y@^(a?LuQ2`01w&GdxCFf67gWpHBt+n| z11R&OSjI~WE#t?X4bJRE=e0@jN4-iVqhIxl^xx>SH_KZa~q#S&iglVHGFk6DnY|vc4m|umeP* zvHP%;kD%JEq4;5D;FEvk3Qu89Cm;P**drj@i7!@e+`0y3PuF`Kyed^t<7ke?`pPkT`m7=we6;e1Mdgf+;?B%} z-C{vQOhQL5M!L?2+Ezot^vg=#WI6G@^7Qm` z=v0!)B_&0+ryouJFdCmtM#&Zx=atw+WhMD6n)xr32K}&M)LY)FGmYc0)@ES29#ASM zRu%jibQdnN3Lh-o=()R05;I-Iqw6=^bLX;iSR#&}K~E|vgs^|7#J;JL?!Q9aS0+;e=67NrIxi=piDU)Qo2{afdZzOsPVU}5l|9D%qUQCIenG7R}v3WcL?rH z+0lC~R9$LGq;EX|Y#tWGvP1Isa=6vR4toxc#n-4ReIiz z!{DoUy7Xhn(?%g_pRActH?k2DM|wPTY`YA+zBE;@))58~$rCF|?7nxu$FNfBo?}ov<9Vae3S1XA z`==P>1XL1{VQYQV{yeFq?c5`pKkMqU_>i=^1QneVNc|JyL6-eUg`DmmC)1&h6VRH( z2OLMu^bXsAWIH)zGHGv$EhmZ;I$zVPaBSu?k83c>yQt?pByl53(vo+vVrFu+^iyY6 zRWyrKM(Np$VIF=5Mjs)>O_EgeL^BpH%K83Z#}6{pp(6WH^F7b@ub81kKXq|SSjQT; z%7@lKfUcLV!O4C8lX3+3=_l0mCz#${EgfYua~0J5Ry5}`P@~eXJT%B?iiR9hC-v3&m9>Ce^%1M|{7 zPcfth&5~#XHluuT#j-d0tr5fR$33DjfR#%f5Nv}ATLQD_^;s{;WDf8;WgZ)-1L zG?@~A=UJI}a}kt<2ea3jMz*?@S?ls&Rpcv>!& z!MsO*<1v^kj?5Tt8*n&XX4|UA->lBaT{T>y^9Ivl(n%Uf_Og=ziySOGm3Vv-AC{WP zDDjfl>N+`Bj3-t`E)rgb{t3B&z}JabtVpq=lrTI68>lDSi}v~11TCrEmABt1pz`#Wl5?XGdke&2ELITMidd_}89pKW1CQ6jKKm+rE zqSR41c6^~euGXKqCI012kLs{jP3XX2EPWa1O=hFG)%MS1@uDhdXgNpDOinOa%a$Q9XZ9V@Arr9H1 z*XI!i{@?2#hhr{aqZr|D^E_t7IN@Aiu>AeGREzW863dwc97YAGuVoqg%tJsP8L+nP zG}g8_8TFxnniR8%ZUhNU7S11BOh)9mG}JsRy+pGFSA zk{h!M#kIHklu|dyVzZ8V*SSr{1xcirxERG*NUjD_-d!^XH2O0@pFZ`pjJH-(CUz7!E!dN9yZ(m;c0vA zd{+tpC<_^YK%n4aQH9f1U1-#+hS%=}FmlMyF#;tWg)-M!gMlbs; z%42Lx@1}ELWiZtF0oc(&$fZTfxxIgo4|%;L^B|klo236P)=G>PdE!*YuGN~IR8W0c+hkYg0 zgwFk`K=B|dx2o)J+4buci19U7azbBzD3OBv$xZN?@nx=5gLDq}7=BC+Y^ioNjuiYo ziPy0nd_Htj&!|#sAJRxT>52x39lU%Rh_Cwl4&RnS86& z(bEl|9uk(t`9A$&u0OZw->lNhamD7~@uyL7+h~?)pKt?3`}l<7A+4HZZwD*1ZfKX4 z2r5T!%x2a$0p5Ea0V$|vrWR zf!+gA+p*iplx;vN*$7WNJSqyu5lU?1=O^E8?b z-^)9=X2XZdB@FRruppsYReSB@Rli0CJYy+DI%@yy)hK~^Rmw_{c}4h7*07eZz-rkU zCy(R#7uR-)6C$6a2v18!_ zCIdDN+WWDn@hB+((!q1Ml<{e-Jh^IZ=UsZH z+-Q4tEk>(u9xq`VAx(!xj@*zhv}La1Lz$Gs$ecjzxgE7b^Y4)dC4Tx}RELD6KIgs7 zQKWptQ$+hhYy6QZ6i@B;HRF1cMoK}g5u+yUzQvH&i)rL%Nt}An#U71A0_an?zJAOa zgkCr>#UVTKQdTqT=oMeZ(4Tr!^H=*!@NQ~un2-icKlX+d`ktMYr7?UZkNAl1^Vs{< z1`{B?EK)`!mo4pCH%}U(n=wUG_f8D_I}@urMuG&J9G)=@`?TW?{UK8q%dfGk5>`}; z=5&KxHY^0g_chPNB}ZFH&>eT+g`?xVXt}6@+?&sME(bQ{NPrX1e|_HyWWDew+Lm!Y z{a#jY4<7A6cIaxW3R?FD3Oa)z!FN+6uaR0M;pd0J!Q(|tEF~X(iIkb%B^xfPx0-xU zT18U($}9r&mHU^vIUbVw>(-~bkd~IOO-^SSz-yX)i3Xt;y1; z<4wAeF8drX`y>u0+Z&Y&^E00{quQ@)dennkkaOhNlFqstynl;FIj=|31uw0Gysf|0 z9D5};e)%lkc)n*uo0s;KY+~_nE-VC;RIS(yAg4xSP*YtJY6InGL~gbT(OzPv(G}R~ zEL|E8rWUL?Q3w57#LV&V7rRc9tLS~kV$-@@9$TDUFkx?5Cv5#71#zLTBIF}jf4-`w z;{1JoP|IQlU;gyGl_UH`>`SrL2T6x6_g~Uy-20;|0y&`l&6A;wh_EA4Yw4v0@UV-; z5FXm$M)*rt2}ecu>)iPBjC!Npb3JbPL}mffGx2)f-rUYTE1QxLTAdzP8Sdi7w@<#G zFp79E6`IaFYupa@QuwPYOOb-zGbZs zBht~0=7TdU8|s*V7dO{f@>8z^EsYp!qf;LF_hBS4HQk|H+W?UdnjlifJ0`D}{=y#r zyLOcV+>#kvo(p$*^?OtvY%JF#^wu}ohWCowhDT^d@%q0(bNtVxH~Cbrp2?1Y~Wg6{uNrK~D8H#6n{?nk;>@*Gj;?8F>idhKFVsyCx< zrT?K^8MNK5b)vv~KY_o=+-xz9p-1SyQzeP8}*!D6{^4``Vp4 zFnq&u{$gYb$zS7;LW}dNT~V;1FOSlJB$WUIrymIdnpv>=K6bv%h=^~ zMKcnkvkgiAe|q5IU%b%JdxAu9=CnU|c{R^W5?VGoH^2CzY)koN_9H1_hh^mJZ`nBX z+D!JEyn|%Kj4}&1x~o}NSB$(b_E~bRZrx^JnKhQfNt}TlJGg41jtW-pP~lj{KJ3|L zOxO7MaSFp9C9EZ?L-Kdg9D9R`;$4?Z57UJsC^CJgMZf)SyjC%vpAy{X!sS9;-zG&L zk|A~C;Xk9#dRMV&^|6O5x*j$~l z{cv#q8-6cU)hJ(j7lYF^QokaUQWFvf=f%A;2Q5%Nh#P8a`4mNOCjCr2ECcuXslfdIR7@JY%iG z5R-}5MF74TtX*VaneHj zQJ+O?-U;VJXg~=&>pmwqgb9rZtHfPqDAJ|)AFP{02-Dc&hg$6 zzMhKb9?k5OTxWKy(6}kfkyxU25HVx=mypKas=aebLPa@R=O{WW9@JUQb=Ea5^_15D zGKq7q-v8*nRUpJ}n3e7F*pQw!_3@FsoT+G=`*qT)~&6C~t1^P7-XP0k6YK8lyM zR^PZCEa87s{JNiI$Ee8n{H%9UQ5GtA&?eR7U+Hy66?BG3+@(6fS5TT0jrt z-#zuxIdHXP0*o2R;T1x?gLY zi!N=IzgJ6gao1Z<1{Bf(l#EKmn|5%S1-jRKqS_;k^LC45LSJKaa;Be%3|m8v`I`_= zVbU5x<5O2M0)56Blkxrvh_&}zVX2I>eb|s` zsHDPF3e6-KvLd6(vDpRy>`JycJ`n-U?8P4+MfBSoy{UG&wO@zdbHtl1TKl(}or<)4 zZ!A*LHfi<2AudPBVBtYR%SFt^zlMx6Ra;A1egqTQ{+|YWGC4Lzw6Wn!+N4SJAS|MQ z&T3%{L}T~f3>iz<|9OS%=hv%{j0r2Bb9BSpFUQbFwcbLi?a$PjuRuq_-vj$y{5v9n zc3k0lKiux_T9x`gWLXviLSi0Sfo>HfZ>n?l1g*TATunXjaen2pVh;%s|Lak(lJEDX z3wTO>;yp2I#f+%ySbx~d&A`RB`m_I`DSpTg?b&=eLxdCOI7-Xnhek>(hIuYn&erDs z{@FR1EFctqqDK1R_%h35tDTdvRMvFFqI20st<1Nk)fu0;d4hwk#`5jxC}{5eE8~Fr z&Uu*ghtcWY>VSo+KJEI#jK18}6_8Gv$jx-jPvlnedX&&fs!YuJ+U&!p`K%4b+k@>w zq$Rcbda?j*Ja9Q(R1?*$XB|>IAq7P;689BafRl9a^|erK2oai@Yp(R2c)j>$fdAj4 zRr3Y^EApA6U*N#p6L#LVLF9Zrk9NArXp($tubZ82vrV>(IGoT2O-f9VGWsdc2o zmQP*Pbo}Jzt@RY#9UPQcI*>m}rlgN6tKVOqir2AZXZb5YvgR#cY(Xxvw9r;aCoN$)>*mBg zPvi+lHdTz|60#e2xl)iyoNzI?U1qW|>y}NaLPtR^}q||F^{-f7=TI!KXZBhFd z;GP$w-#Z?^L;ip}Nfl#bU;bL=#eyfg1$lOmq?O0#Vv>dg1Z!qI$9CfW`>pc` z$@R1u-EpKNP6@v1ZM!$~JNL0A6#rLNx9F=daxwpVw*xl+tMh4qXATS+{} zXVW)R4YN8+^VOBNH4!k__U1D;9%pR==!Y!G=tKxmooX&xRMF(Z1_{Es`& zxQ}KVqXs&=Tr}y$ZFmf>nrTtV*poINGpq#6QW4@a$<@I!8F2uFn?*!sQV&aVN+)3g zznH(T<74n4>AZv0agw0w5WJy2u6sLy)Zsj*;;cyJ{CO(+DlJfmK6ax;gD30!7`_c>s^p>8xl+GXOm z&kpV_yzB>Jcga0vMD#h36~gsBh&V#N#WSmG)WA#iLR>|%qQWwx<~V?%E8Nk8X4Z!y zO5FjnTfL!gz)#-wotpuUmiFn%@fm5AK@<#Jq8`H#OBwd2Cy$ri89KQA2AGuKAu>4W{ zbhwy+-iUx(+l5S7O;S_)V86iXXQ@oAcF@CVxMtA&t@sH#f|uT#u@1la^nun>HY5$< zXKtPZm4Qt-5!1bGYNeAfysz@i=+^m+ z!|+&MR*9JBZNJYqCtEXkzKtWY+YpNXaY4C!XfkkOIJy^q#NAUo=vjnL4@1r*fokNu zAu2e+#y1k7<+e#46OT@ay*reCyYvgc^E@hiDL@3~*Nv@oa5)Ccp|j1v_e8TnWM0qL zA}3Rq_(63JXRVEh8(YLDMqivlZsTCHgS}!;liYW|elUYHa)ljNn|`exU`^-zH?p69 oc0_RZ5a)_F{P-aF^f`bb&>JWr1BFK=9xe+=9DX2pZfL55a=F1PdBG1oz+$ zm-oHr{)l_#L!asC>6xzT?y7p8>PVQnA}%&1HUI#?eWL``1OQNV0RWT)5bATygHGi5 zbAjTbsVEDm8l&C?0O$a3pfYgJtb;b6@0B_TR?%&P{ku!4?Ip#p;BL;`Ams>1X8wZQ4-VAPSTW((-kjq9c z3-Vf7y7D@hyQ&o0K9HV0TigZ`Iv-0$US-<3U(Q>ue!9%?`E(}Ye^&o*D{~dMAclXK ztsus^8T;iWCi#aH4F!r1DLp9!AjRiWL!r6i1F-wQbsDd1DFU7T_xVpf1v={gw%z=e z`v0gYsn2g(;}jJRkH_=z*Q^muwI+{;(vJh-4h)as!#q#T((NZ&@w@9wn}*YD%k5AS zXmAJ_9Rrw-o`OHNHrZnR_tu$X(^kj*q_p_KxL@Gr%&N=W{FL}luWhmM_7xHUARqt~ z5fRd#WN+87YQ~2#i`j3)4)-sr5Od8^w+bJM=#M`-Ac2yIsXp@fRJg2fA&ba^;#kFg-X* zjF1|Yjsb;|A$Xcn+@3{Iq{?U4#s666sgM5E_U@pE@5Xw(-|mL9$F5GC4{0?+ets8c zl)KSfBM?IpoFwzjTyIJ>bCff_^>l{kw$jMAfuYOxsP*ndaqQKlc9qKk^t1}(J@JP* zl{>JW11CwwY^cHg+dNIj?GBm$l?c9HeD3iv&v}*cJ-Ga51PL94 z4nRDG58%B<0l-k`mlAmC7=)lii`2_ar}A_6zZ@SYi;Sk{=xFb%{g2*0U9WB4G#g- z11T0%YwprFDb!z#OQE0!CiA>L|IzVrXsz;?eQ?xcyGRBsfi?vbuy2TS^gUA( zxqqyd(C@)0h=E*Jq%?loSZ95@gm$!~kVF%GKxo4Nflgj#{O%X^t+XIcv$TjwN(RDQ zneR$OW+IERwsD`fuKf3tUR{(AQLTDhrSs$*U5Ry^Vxh_ig*+nbaSa~PsDswl11%Gb z0Ta2_gQ}`N=HB_z^tEBzM`^KlyKEq|LB&wDB_Cu|fa{2N1A)Qc^IqF{5Pt(_p zujbz<<4;xrf(o&x?0z#2h#0xAM?dZ8Jk30RkBvbM=Pn*Z9bH^2)n=_%D z2K1gyQF7Si%eU9?hJYD=G!eaEIdpWmBp6TMtZ{*H?)?o}htKuFKkn71o_N2bS_j8I zP757b|DoS`cwP9jev?9XjhB1I7sHbMbZY>->h`tQIoHyDhkvUt$_H&%&Voy5C6-6U zXhF4@Sik-ZQQ)_607BrF3R?>ovzb|V7xBo5b{-SCJ| zz-wJfHiGojh04nvp@H`6r^jP5%RHm^4mT@4M^B52WG$SHr%SdGxWw3{wi}M0R4RT3 z@bAOyJ)3-NNVL~9=OBtP#uf4CsTrwg9W&HjBkxDmB&^pO7KTlVgh z)A8v~v*Ng0-B%xrtIu?>oWZ00Tm0b8t^_UHd3(xFRk@g`{8p6TwZtVGK0eGDJw-lU zmy_9!zNO>wUiZkBu3zM)_FyoSCk7G$iye*T8c?M8Xz&oV4U!mFdO<~90yPladaV|> zzAZHo|DGpF7Q7r>e$=%(h=bQ+xJA7Eofl7AgbtXEEe$E=%+L{FiWAdc{wW&=!#16- zTDA*?O~FQ2QJDlMbLILVIn@JRZPoAQB8!#f@hf*FPuqQSGAY#^n{9Pgk1@E zz2Cp?$s|@og7?1f68&5MM4m9rPC`VQF{|3Ju>P#6Q0e=4GT$N0Vf~|uZl?5u5YW0Y2b4NWK_aN^a;T9421NWx3u(>PzHW-9~6*Wv=cH4 zUs4kg5y0z7trd)5ml+Y%X3>yGr1&(tcyE8G_FrebdYtLg?i2a6|ME=B=au&ZT~_O( z>DFKDJr;rOH~b_9Y>Pj1n3Ar=aA@oK&!g8y z{_B@!SMTAHfX>+C$A4r}cN4xo^E`5&VCtB&Y-#O(zWp|!dVi^Mt9IjfV}HQP<@UX= ze$pnsu$)nFKLR9fI7T-9(4Xl}d(-_q1h%(|&+9*>7R=)e{)agZCw=L+TP&jd69PT2}5?o15F-BRQs>WN3rOLwXCzFdSSHICpQhnO?b*b6Pv9)(QCm+AGPv#MpYWDz$^G=ia z@i1bU98D5}bY0SOMWY$GKFt|jOgd)dG(9ownxvHQFoLDzHe37;O7uQCG`^%{GJTK3 zkvgpk5$%j|4;wV5jv@@;O^}r{2TcjU<;-G3BZ<0+=<~G$V45)~Xu3;CpS9R(shdBm zhE9m3%Pv~)>pFZ7@$BQYY_{Ny({S^|7eH<8SCxFQ4c3Hie-0I$m3lUMOCwI)5JmPs z6#$Om)(oDGBR5CUkE=#TPKegqY+A9K&axT9V=bKkP&XxZH-G@Y`_WC5OR6jIoIG0i zbdiO*qILuBUX;sm;B|GsqUPxJv&a8o_eE6{)ynyMOB(UjQASp6^|(ZqFCaqFRD`x} zQ#(B#-3W}j04IFjL=61G7LjuOqsH^N+IL9AZ{Tj_(<fKa1L8W}KQ;TjV`{zmhMMt4AxH5VwYK>F_Yn)d<|X3&qv z(CVg6-RnczrtR8s$sZg=e9crpWV`YxqBqhaG?fIWHox8TYP%R?2prAqzwAfHRDVif zQ8>d#a&SGE-ndn_ZT6BqZJ{FnB95>BlwrR0z(SW3h0mD)hzAuxWmRqc6}Nqe(oWC%vI?!+ETUR|q;#G`BJA>~xm zT?3BN!Xl67bDDk-LpwBr};aN=%H(rQ`A@e0e9^FiAsfqL|=%f_RaF~0AbV;Xfx#)!yqL12R1v5HIY zRZL|+}%1I6C@S2%!JHIdg6Y(H=IQaw7> zRdOCTrr>=ltM|)t#4%Y-08iH_4!Xr0wko+zxestEn|~b~5Pnwz3|B7*K1r^D%#aFU z;^E=^eeajA#WV`dHUANbis6I(YMWT&pU>5|n;)gI!|ZbCIesgcM{-e6(IyC;=)~rw zs>&5(b>RB)l}v=4^i}^^NKKhQnXOi)jH+=ldipUZeR-Z_9_w}F>_eegWrR{RnoJf^p2q^2Hd5Xya8RdaQP)< z%Spo`&Apz0T(#$e&-V6~6g3%mJZ^BPCaa0!`j%Nc#tJ7Lk`XD3Hk9F#;8KoembUr` zIFquX2w)8fga+}Z5=0J~dVG95sm?|zZFaA%bLO<*$#c{^n*-PWsPa|I`-K!0<@v1n z*R?GqEticBGa^r&SerjL(pH%qBMwuUz@+`?gUDC^b6a4*-11Fgc)O=*^BnW5Qbav` zzDcO|C9eb$#>=q|;H6Gj*My`l$9`9@c#OuhEto}54Woj=E+21oT5ay~YD@m6Gdx=u zt&Q2M`_7d}`$ng~P>S!=09d|wEjUHfO_d=CH@!bCEJldf%E)#k%)WS5oe_H>tdtK0 zWTu{&G?iJ91L`XB~@z9!W_w=fH_-uSs3s-<3sAJ(-)QR(-oO%j+^K9Wh?k{wLEx z?Cjs%B>d{s(dYQ!euX+Lg znB)J1e9!$OC0YU1dZ)I-G$CL~R`NA}@$S&W@BBc{^6uSnkHm~`kY=cc+e_mz(5Rc- z%xID|uFx+XI+bE1J%>;c+~>*7)s~!OY2XEB?cX&e!pg_UsDE?I_m%OhPt&(tMi&kE zb~#JCq+>0A!M$DcMRWE_rk5TuEG@L0QORVV19{mAP)SqaX6)3ID>mo{)vv0U9CP*> zIaXG$r(al(oz1jtZ#_(gK2ng|MNYEtSKuw^kSPZT)qcO^5TqVkA0bZvmZ>5C^U6L! zXxz9H??ruF3;NHQ!m;MY_9w}!#~WR!_w|1^A=%>5i}FMCYTY(?dc5-oOk$iFT8#Zd z|vX70y-_=G?OBYFW@ zu6L7ymX^kU!737*6ekj|fwQkCCs=jI3poP5U9H|$H7-A;vu1L&J`_mb4}OZTz7(6Q ztr^a>m3jyy#FEr?UbR{qU}?zGj;Tq(+f;g;+HlKC_)_m?EqG7p;w*2w_W15_;HzxK z_2=W;6|MNM$6Iaq4u8EX?c`U(HmfmjF|F5X3!B_Qljg-SK`?RP-OkHtN>TC`1eexj z=Z47Pu_NE@#M)nv|DI8_o-g{V4{P&7FFVfnq8nSnf_DGLUgYGF3KpRie99qjvChO@ zRJ9kVSNjt*Rh+(H(IZ^RSIIXE6{gt7E{D98H$hS$NEGn!J>o~qv&sHWNHNr0H7?&| z=lDB29NRvwWY-A@bT}Ujzw>^Ls-4~_0j8S^N=+1l5(o9f^4WKGd%jiE3}QCZe5uw@ zAcv8an&9Fm$1Fe1L;6uy4E}d?^Fukpe`}33lfI5>Zrp>^VRL<+vM10aq1*iqR+F$~ zw}hL=hxG!NGPz(Nk!7~-${EGJuikj|w48?;doB>IhPOg;bPXp;vu#b^(B(Feb;itP zApYsP&HrrBdG_XO-}Z0lXWm!!+$7hP^hUF4*S|J$`3Um(E>eT?!_RZM3iJCykNrZG zcBMut7(w*$_qdI%kJF#XY?-Fm-fAk)NtoXx`kxD2`Cme%_nRzZ=U%foN_*FlfVcW@ zkP6e}W>z+b3Pg^a|LISo<-NAEDq5+F&fRD5;;R`G@1q5{ru#W8P;w`rPd25KH?lw{#re4;}jb z8gL zcD~)FzXgMuf|gFl7CX+TAS@zL8NOV*pTMAYeE!n~*_5;vxMff;5f)MPCz zhTaxUr|O42h#>mym$PD_@*XruZB*jij;>GU>j^Ni3SBpC`+nTp$6q;q2t=0k+KUI9r z{{m+>n>^wR<4UYIkG1Bi$DL;h8Aju&=xELO_<6Hp96>IM^A5{Rfw#?W!ke5OetbV4 z-mZ-Di>l+efR#q9E#o534x8zzO9E>0hpsX_LM2dDQ)wE5Qr3(STNt-K77LmVVzW>V z-yP4m#b^5?#Y}9EQx)Cy;IXRx&?`jn}chuN|fe3Iphj(c!&qDc_+(4a=b2ekcoX*M$F5dk$u|-`cgv zkE4mDp+&PR8`!L%<*5APW{5JF5PU6er8<%%?7kp8HS3_d_{OYKh@O)4@jL1F^0<#L z1KMl?C11+^@vc13qpQ{J@zgH#Teda4yM8b#vpdyy@Lzq#XJOu&>BaA4nr2E$r|7eS(j(a|6c47 z907oI+|26J-rVbC2tx*{a_o7QqBuorm2sN&j+66Z0LLG7eNO|n9uYyRkPh7F_z1PMO-HJP10#l`bhsNe?uiq!q&(QB%j1j>m>F?;@u@b+qiY-b*wTnq7$A&sh3TGx??#yodt{r6@ zD7H5P^HDR973Z=AK{95OQVK{|s~CEM&0e5jY~t^4kaGYabWt}e;?n1FZy$!bqE+dx<<~pA4-sXsQ=$*H3|Eb^X zmyrOY+x{*emNA>M+M^K)tB|)L(%y4_qHNGi4T`3F`<($=aaD=r-a}$&oZ%r`PlVV+I@A%Z?=x8vRew&H~JRW zm=9CIwhg8Knf~f;m{qS>R+@Gyuolj6H=Cr9{PFSrMrXe9rG2}Xi+4lcR|Ficn}TQ! z3-;^z<+mq84u|)=-p=10)E`OHDZwK$iir=?jrc(M4(A;KTjvlaK3?eZ<66tOlz00J zSD1}hS`hqVa0eS*fDz|WX6MV>Y^IZ0Jpuc}+1ZT@+c>`|H4)!^{SFy1-BEE1g2?Zp zOQLvZSU=;nb&zH&Q%g1c5Uwg3MyK`1fO1R6!Om%8uGL|leQQ)l%lgXUB^WlJ$&6rL z_`){&L0a$}--`Sd9)a06Tzl2b@_03)+wSt!$1B4#T%J!Wb{-7}-WF?~Qf_S#*yvM9 zNF$vnWTyb*&ccj_IQEIBW%rfePTct8kf(6p8t9qYZSviG4vddT+pgi1_`IN7V+VVh z5Z`Y=r$PDnHRSkwwQCtwQ*kIKAP$AvI#P)M)fuw)B`C#FdAA7J$R)_Q{@A~HDx-3C z(Qc>wwUU`@>2AjEWUR%12ZG3w{J2t?g;*L}g``_*1`)2g>IsQ%YTh?30PW=FnHl4uCyN9)1#Z#2V!p(6(^e(ru( zk?wsfH|hJ?*Ar4k=rjo8vgzC~{o9S#${CXJ{9P@=?A#cjsrE`9Q#6D0gM19QC3NrCiwLYi{eq4~Fk) zF7(xI3Y_ar+ZiS;e^Qxwx)lo6mDYF+i)( z9-X%R?Bmwsbn%n68Z8s76W4yFev5~8FfVq3GhIQpVJ+4xoAPLi&d$Ckcw;mCvQl&MON`y~*g*%PGr<>^b zENN*Yx2mfHU5V%~u1)f6l-P-rNjw$aO2d@+Bg9oCVZClpAGHq#2b`;}`*Jz@Z{wG5 z+wpUJd`pZjS0cYfZHPop2vXOG9ncLWYa)q6N*9FrIIK!*EhaMrEXQ(Q&p+(uEIs`m zI=uOIOzl(6#YaeY1EOcc71-RL^}gwWF?8z9;G|k=x>zhN5m>Z8v^jQMCGYRnUha_{ ze$Bk#q?Oyue=TSS4=m*%Ln;g*>SfWYvWRffiNk~mRg(LEtYk~heL9`Om%iRfKb%MI zx19}l5&f$Fplu}5O=OS8h0iZU&Gh0$8w+SGl`kYhJYK>np^SVpKU(qt-zk0gkoJCX z=uVyE=O4Wu=g7kF&?nsc(I|>AC$+)DS|r*>4%CIZ)%0rZudHW9-!9vX&L4(b)P1X$ zR3t{iWzc2J#>GMgAQ4f0^W%*V%YilGb&^GjVSytJ{Bp{W3&hAHZ0s8yFE~Id{QI^E!a|m8FV%g~1jG_`ysb6Z1uhtoaMYky^#xpk7^B zB(kP%=brs_OUuqn9`V(SgJ#oQa@nb<2n0;f-W5uRD^>ZmoMDlo94kShphJUbImpOp^AENa-bNz#4qYt;AG`L$F(Qz{*A z0Om)I?CT>G^|EZFs z$h0Aeb|tS?sg`iz|(Mpa<<6) z*P_T@tUIJXef-u+_UD!!UPv!{J6$xP5MOUo{ z_jW7Ui|>xcTKbS4Bh;FO=`K|BLJ4 zXSCY9ATqpHG!dD$zPZbDbcJ?#6ZavBDO^O8usLvMMsW8)nPaISWkrqpFdzF{= zh;mIrteVSAKL_}W$WpFe;=3AA*|vBuqF=f7UgWq%{y#$hwja_0CPx1d!3%D|LMiO; z4wA&agISJ_&{t8kncwmg?Je8+RL}Oj^nW_`h>kOJuTd2g8VCs*7dezrqlI%jinr+0Ldi?mC&a1Uf(gg*C zm>YHgmi4zjY&bqux&pPEiU1YE3~k$EC;4aPV;<^R<9xqHPI8RzaOs`?6oV@Yjx(e_ z=0Lui`F?<0E)utO0a^SEXd z)e9%?9NH_4TrN*ux=RT=q?qIIQ;=u;qW}4NM<%4l6P^R$Wkcqg?hMEQiGk=E9|(B5 zYpsMyhVzxtsrVMcnK!}#${<3s99yg!Jy|=Uhn@t+>ERtLpAM08EDLd$%dGJfg~(8xS{7GE?o~&nqu5=Dxf|w1nJ&`J88(+)>cM zpIvQ8f%fLYS&9ts*W*awcf*(TOo+m^z{p8O#0I(bA#1+}A&JG@#p+`h{^MH5oyY#2 zbxJfBBclZH-Kb8jETQQpIzz4pplG#0Js6kEFDjzHiH)rQ!*pB5d(E&(tAnuPpTpK& z`Y~C%(Y4>va?taoe6QR@H1>mO~yr6nU2KslH<#$p`nQ({nF;M7~UZ* zy;yylLdeOSRGOy?#|BPje5{VrVPDo9H!^OF*+cjq5UxRj#J66RDmCeR zrS!qZpOh#b{*nJD_Xr&d!;^+o?z1(sY{r9jMddUT|T_a4Z7`W1Qr^8juhD@^^b_ zyxFKGb3nhtxY4wOn0EgIJnLJyQl#j=JWam5;4VEhb#2AYSr^{4lW#Z-SjQY33}bUA zv~w5r7x+&hd*=oh+cpLx^kwNZ#g|M-4TvDKw0k>!Et^wnguTX3|kKOZYdz_wzE z>}3-Oyl-X;N+G1-`Q&JwzUzrMLO&t&PsK?2q8x?l=TK`#odvn6`};4Ay}k|Rv@DVk zNpw;nNxWmFw-w>HI)X8l7XD06UZH|8Yx@8LlGs6nEwhLO%;zu>Cy~d*>5<$uVDA*d zYGTNZL7%MgDmDh@BM8Gf+>Kl%$7N_SrAF7Eh9UPgP)$$rT5C*7_(jiFX{g2 z;IZSXs>S!X?wDt+{0hL)bs{pKIA{0avIQgxi{t1ARQH-vn1D+Nqpa`tw&2uOS*!v3 zdB0@ER3tg77O%W-LTp3qaCr&etCOaMX8&|!sB4qYlcBd@4FcGVc7>RAyoH&W?@bLB zqM4$@$T>1G4i2g4zptK9GCg6asEp&B@I37DDzHkwv&X2|nuhN4RJp8rd7NWuN2~je zP!{g|U_cEO4a7EeIFbN(n(kX(ps)!Co1#a_Eo3j4A!WSfj0>*Anwy*2~0kI@}HBwA5yVOPzdBx^aMHY)t>$B0g)k&myW0dGprrsXwYGh zsFD{OX__ArIWq{&Jc5SF$NqgbeoqWBJ&{b!oBU{}T!HqForzq7*QKkoTrkHaLBc9X zw>ELF<1AbgHRYcbOe*J_RiHi_1Do+buTRcTR}Gfwcu1#?I?O0@HJ?5{1h?8e+Eh-Z z?OActkm*sDljl#w24JJIgJj7|s$_I_2P!Zrg_mcVza_w5sB4x!sUH10a;N5>@G$9Y z2;*M=!U;x~Us`|;9x~i5RpWHZ`5BDL=~|W}G|I!WSn{rZo(R=-)urOR)=6 zG^z!IQT41DSU(q_!A$$S{Mh^7psh&X|1K-Bf-89ac!uAv^@@%3@sr&ZcaD=(gv4sjy4g)vJQr_$ZQIQ*fjuMv4Z_mmIeg6nbK0`;$3xlO`r(}HYQdJ(yv z#25s`^oXGt*k@%cwr`z+4CF3m2xm{UPoYYRL;zxzLJ~$CRw__H>Gk}PM1@$$W@^b8 z(-fl>Rfn#oSz>zelnks&)#6<^aF9=ISm`w=oh64#xe!IMLCSl5IO6#K~(h5B)S{4OeO&T>fAIK_)cusRBKoAQ-P_3X+ za1D77jDR?|$L~DwZ7yo}0X5*@a7+lw2DzJ8CFLZ!$XBddG8onQTPWFpF875E(=js2 zdGdG0sYJRm`s*CMaF(eujXav+c6tPLJCmJ zG=aP_^2AKClf0-*TjWA9$QX5B)v#xm-lxcQOH+upsgQ+JkAyIkFp7c%iXx8^!1mQX z4U!wz5GtEV9Yv%hRqaVS$2i!#=SzXwy(5k}e5e70e{i(>`Tp%J2Ypai*tfd3h=nlK zp-s9EJF)R9ojkM^WC*MU>S*D)EAI@*6b1x5w)Y!b|p#Bps$6_mmCI?Cl3XDj!~ncb2jBb)1i;$qz1wx zdFz2iY4xUGY15X1ruC?(^9*2|;3i|3ygTUcr=sMbf;3?{=NEr-RCN?%Zc77dJQ%@- zHqTCoX0*5A;lcMQ?o?{-$pS_Dxw0zKQV{1q)W5xa;KXdf(ZtwTGyOo8sQr1bMcu51 ze)Z02dMynGnJ(%V>i+cKZ8C6k}wd z0Fy>t0#gC&nCxBw9gXChDR@Kf>*}&}I-TNIf&m(04gj>ya7-W@9f*z~pu5f3R|>}h z9fg@YO~cCKUH}D~H>umHUppq4+u{X6bIYNY*TNJBWD6Qmr=$a7oScPT;O19sWrL8Y z1Zr`rif!7?8(eX$EUB)3$5;Lq9?HZ^Qh0#``ug1L0aD`^o_4(nG;co6;Z9S~Eg+Kv;tdfnueoJ7e zAiY5mW=LX{1?<%pM`)H=Ad3r}hMq$9g0JbqK3tM>l%*_au^He@ z6;@Bb3I&_Kmt_b*G7!s}vA+u;T!$o{M53}sVfPJi>>oJ-QAaQ-`fR@jfS7e9!H*LI z$2XJPw0l>V!d0D{-Q`I_AVBwILm|?N;J4RylMa+v{^Q6`n$({|v)|{ljNY_S(WGb@Gwf@=b*M-teY7XeqPQwnPuwT^i+r(p;{(d`2eF@9| zZ1-s+)JwUABa)-&pWFgfK$(#=nh6^)_KI9{hW7sYJ-(zbwoJ>s-5IuvMIXQl6yoL* z6pLbuMI6z4IC^K8h60f9;`Uim_+c|+_kDEhd?eU%{sn>5Rj7`=LxT)Hvle-B3Z+0u z+ImW}g&;mzz|Mpf9){u^D>rqLCHNu%>Bop_18RhGghuggy;IO2dA9d?5k4s@oX>03 z*(7!5TcUytfr(3yp$0UDUY3}ED%bTh z2ZUv?62VL}JsLJjT)u1yb-bx#g(|gT{*5@VNMcqx0AWKjJ*-pFJ?q4DI9DGHF}2A7 z0iYmCRhse|PYe_3oJK`8UiM^CI(WVo4)>*c8z#ak6PAGl4Yui@8;%`Zw4vtK3rdS* zItXpQJ)mheU0)zGkh21G8ox;>n*UONLCf+nXjA!8uRF`>`QQg!;|(DQ!XMYktC+)O=lr!lVr>VO(V#DB!%aZk&U9`=Jm`T_~~P z!N~UZcDcGF8o?`fou7wo^Yhv63)CIAR^s+(a_Y@|N>6W)5$g`hr-JOzAewv`#l#(+ z-q3Okw@Ao6cTu$zCzQ{c&NWe1?4KxUSnrM$2L>YIiY}(xK`Mu)9z}tLn>q)qXRa+P zL@HU%FJ2N$Z>IHEo~CszUvwLRZL9N-?-^4RqG0^ zA(*1>WqZtagjoCCrCECTH;T&VO$&sdX}UwuVy0f0Udp|0iu|&~@&4%9A~KU*6218O zft4#{1ImR;ZieH@I!j3ZTa6IqQW=0_6VYl3Jy&OU)x@fBC;NF=^zGHyNJHG)1#8<1 zf@+<%KOAzzNzT7EKA4fA@M_4u!6ixhTg*@!BOt}t)fD<`iL$b-Hz?DNB%JYG{sS-) z&JG9w5attxy%Am8VLhfSSVj_&GMUd5#8yG6(Au;hc2rjSr-tc5lNzYwQ2}FRymTBs zA11Yo#MZrc$=dW?sWNfJ)9ut6;vDQ=E-Kqu!FtgWo&%-|m02~UUm3T)uJNP-7bww+ zM1w?gMq@UB#T#~e4o@T|(bCG1`S3v-^3TC^+AZ5sruXaSPKemn(6m?y*MzPeRfg^b z_85Ce4L8yojJ{0*kS8V{%l^IF#=pN6nO$C;)i4znWAbae?a!V8gXTC$g&_F58l3(x z94>AQn4311MiZIf(&v!*z_Rx#YyF-$4+Y1 z_T-C+*4xCYW0~cClbeTDefgaoxYLIE=i3)R{mMs?FN*Ecm14`UJ9aFhW3AWQ79!jB zGR&x`lHrWl&90y%mdT}Hph*!6QWULAzjKctYf$$boE=`u8M6l-T#>JkP+#X{T8fYP z2Y%-NRXDEh58_v@B0E;BKDIkCU~^>;yopv%QHt$rw_Hr)cMF1$>oU9EhZ57!J2(B7 zq%&T9{dzn^1qcr78ynFL4r9^RI`%xvFzXJ2CaExRh~jjQlu<*N=Xuly_KICl;WEl; zc2ANUpo|)25Zcx`Ijk^(4K(uSU0T=G6voyI)(X&`t`94AXHb9c87de%Otvd13J}d7 z9HOU!E^Cg#gNn@si1Qfd(e^3C_O%gCPaCpW&!TQ~o>HY;6rTQVNRNGzQ2z{Y&XGhPrF3h8gjI>pqC$ZQ9-A7e%z4@tg; z;zXwE{?Utp>*h0lo+ZW7T%yv8W#YsRJTH{J(3OV*KA-jj=-zzp>+T#`39d2Xj#Ibt zSP?HVhe0h>{LO8ASYw$X2ibzS^bG9esIpFm=qmSgO%e!oM7qylQS|_q%|>6K`pl%5Yp1bd~>!vYY3o7yj7L4COGs9OE4Fe5BLJ7yT%~Gej1E4 zo&p!XnKK!CcfN%M6}$q{<(n}B%#;X7&&J4s0exer&@1(0&yvGh(umUfrJJomAfU%C z(fIPWOKbNF5mf{aC@H1`66-~&*!#ifOAg!wON;*96nh0YN;75B$&nd&EXL2)W~C}Z zPsxBFCHb|fJm2Hm)1=NyB+CFtN9mrfR3r~7JkvMiMZ zC~{UfeI8o%G9)3n#yGusev~TF@@|_mbb`3AbXH!!1+mf`;i7cT8+MXsIn=Ka+nJSS z>q5>6$vC+fY;aQ7y^}fRO99}LqAzH%T2&H428Gtufjm)k-wX3JNpOwX)bSRfAD~?- z&smIyHoH11`Q{w&0^}111FnLilGRcsN=TF8R;sGzAsHEPKdgfu`H0R^R4AJXER;co zjf@HO-T-6CnM777VuCvr5|M|^2%nEEWh3XH@#~VEz;T|DH1)zQ9AKyBzyKm7q63m- z>|`laBdGe=Eug=7$YSMT1R7xa=aX>3Uqb;4q%Q+Y6GC}u7r=Va48}OT!9j%Rh+bhS z#J^Xw4G|m+*wGw>eM$y9fB$R_*AWIWydoZ%wh?V50f0l8r^#mVP%0W{ib)hJD&-Zf!m zV8FY;sC1wAOW~U$v8441-yW9Z(4*}ZqMAE-4}(E&qt|$0_z?S zh9{c_q(N0!?X3780M@*T3K%%ZBsWtHRUk2Q@HCh%DFItyHKO!5wOwDWy9$Qj!RShI z%a4`cF0!{0lR>W+o=_q{w`H4_qX>>8A;9HeaBu6+!^HknGMmppj)wh*f;fOpOca-$ z?bLL$l@gUXgY$P836!6H8LvAgY`A|gyD$=BdIWv*{u%(5k_mi{jB86Vbamg6V8O7! zv6?m-5`z1#^Us+sU-W+57|I#j??M03n}_87kz~sS1<5QX?Els^Re&0+6J^R-v&&ZS zpoJ#X7y}@JN+5;^02kqpG9dgV0M&;+xD%&zp>LsMQd5;YN>UJ^8KK->!>I&=jFt?@ zy1NNYQU{|J8W!${BJ6B&khKxi9AoSiyx`y=Kq8WwKmm9GK?LAe;fSbp2NIwEU5GZ`u-3len-Z2aj2SQ?Zp{_M zD+WW%PFrKzfcs!EtMoRdd7qslpcxRdlH%8iuGgAJ%`aSB(PN)^p~5RueVfkj=BldA z*Z^{d)#_e1)M;`6iCJWJjis5|HhEwck%h6moE5GsXDzN5DRAfY#sS?m0mz1%5G|U6 zlU}rBHkV%MJz*|#Mb0cirj5+D#*7)m3`pR4)K-cLv?NA}kztOi+u-f9#fa37HCxnZ zD+In~>-Ty?*ppXk_1&Y@If#^1E4W`-G)K^pQB3y#asi4-6q*bFgH)tCynas1;YK2@ zzwc9sf5%NQW;?ai2AV^e+~TN$3G;J9I67nU%J8s;@`XyN6Zs5c^C`Wl!F+eA)J-&O zK1w}tDn&|Z<_g8HUIGb>$BlV)TLeqFEPQw`(VWu;w8zfz%qrRvGzMfbT6Kh?%z0Cm z%dz-m%_=>Xd(&o71Clh3P3B$Db|iK4jSV%mUV8JG!^q|TRw%jWQug%C=GH4kbT4Rv z0#Q+G01zvt2(OX9^5Hb{+TJUb1Q>*k zWC(=N#_u2w%k-k&3pGYqkRVVo1Z4>pKV$<1({2G2g8(Wk7Gt1i0aWmUMr{Kus4;A; zwz0|%ff2E70`U?N+*$ggM{wEeh6N-70AVF0RWue>J#RGR1VDjINI3F^B*` zypKCXR6@0wi1eyN>O@(^B6<&2kVB+g51d^)%Egrt2rsp4Y;9ogHYRa)CmIkDLh7AZ zqY7vYfok7*Yl#em06~#DqQUw8x zq5th){;xM&cN~y5rUpUSArdibi|W0iQ9v?;!r+_`VPlb1!(5wSs1!g15fv1C7_DW{ zHVCQ>#hQI0@IELaAP}(oCY9_SVh36ZK%;H&%0T&W)pdelqyz>a)StZUy zNaYfu?F4gYn20zpy<;*VzpKE=UbT&twqdG>Z5klzT|a3j8xupQ>;(x`NI{(!5NH~p z=mtseVA7J0x&V%Ah_#Agvk)R9HWpPilvWX?f*Mdu0aHOVotY4pBjp&VF!zfYM3fK! zq3MYR@0Kv>gMBt#G*`n7-cYp;9b zw}jl_#-t$>5k#Uehk;O+9fxAi#-NDII@y>|V}U^xz)MWmLY#P)MyV=VgT@9=Mio&+ z4S{E9ZEj%z5FmnUs|tdX|A%0#b@78BIY`jD#d4(-4d?05F+0 zC>qF-wXx{NdlAu<;G_j2VgZA(!T<@Gl|vj@0T78a)WD0VvE;pqAR<_UBFYldqA031 zj5>|54kCaA>V&z>3y%yDz*+!+;0h?HF%UW*oR2jlfv*M&$dMSSg7!{C#2T;$Ma4N* z5D_2~!BWABO01JtA*7>MUZIGro=mG=0kv(zoEPz4S_=US4Ux6zSsMajF@&B~Lft+? zAk7A2Z;KLmufm83lQ#Gy*!3F5FN8oHA_6NQ3dc}hzRoZgm0$3EYe`keK-&Nz zdatXV8$+Gfh35@xjD=;dQ;W>f81w+4+Lt-(3$z3wgC64ly;DN42Ezh-7mH|AL)H(y zB%e^UvC#Dz^5%pwoE{6gZAiXKV^LI%Q3S9?9mkStYQh9r#WccRSpjv~dqQn30Dxm= z5m2=@dKN4SU=%1cqZm7yxMV^9G-gM?yqL=nZc;1A&M$O~^oPV59*Hke2Ri~|B=Fy*4`a+T}i zTN$ujh_b8BzN|Ip9HaNvzC84?c2&yda&d7TB=4pzZE0=owdQPV%zkODeZMagNcke( z8f2^~qEPNOc$k)X3?>Q~jOn1N!j#K3sZpzfSbL5|Do7i!)LoI!F&ZO~45943vDU+M z_s-bbo~#I(k(3}9DWLqi;ls?-NK>cmmRU)av9q8x1~J^-#~9`qn{wTc5Irb1+KR(1i!XLNH!-6r zipiMO>YzJXWMne;G1^SbRU+7vRe5PikU^5sb1J&E?2)DqD!Lc&7A8d#W8lRA98bs2 zm}k9Q`|+qI!eHyXuBa7 ze3nT$K->f5>R{(G1s1m`gRyy$?7Lntbu8eNhC%!{ri?9s^aH>-JFb z8wJgzC?haUY7RG9w~R$VsCM&`!wErn%P5KFPk7PVpvwrwX5lp>-WDvTF4utP_f zp)6$#sg`{p5n>duwVWr(-iEsCRS9)%#ep!3#?n3=?+kR@T>%&CJX{d(A|2c zsIXH-ilGOJw_ZMo zHLr~XO)zFpFK>ij z^LXh{|Fw?)?7#eWD^Ovv5J?r53B5%`Fhh+F7Gw5ENl`-Bw~QW;+?#Tlq7>tRC?+Vj z^L*9OdWbQ>x(JllYZqe;9HPYssAe#F=GOMI z9GJ^#Hz#!CTwz8?itZRTBAA`o!4wrMew_S!|F`c4@Y*}xgs~W=LPff;7DUVIwP#N= zDzn-sE>ewZh@R0OynLA%lznl5J4PjQm~WH{QTB*&-<=nU$kx-1@lfpD4TUmCr)X3o zBO)SO3o|YivZp9B9wg!Rz)3;2$a9PKzz{edRY27g$-@NI6itzYq>eGBjLZ&FO~tfK z(|9Ucw8p5)xv~gnV^soqUVBCsNo7t(V}j|0W9qnVnUN|(qD?YgSqj})90W^&DvP65 z++BJpBzSvL6`rqA9KB~UO$kzU-|a^`w?{^fgk&;LGhDf+;zhOGAhKimg1l>Si43MX z=L)y+q~&3PNUEeLb>GSZ%*+l@P0jRhIs*9Xf9?Bw_H%14TqaiG!RbgzEH>B>hE6;{g-j zV}Ax(&$;4I!ORTqy?`+ugdrYk&Ru^=b+;PR7Y;LNd1&>op`Z2je9&duFCN)tJm3dNNw> znPyZQx3t{0AQH;V@B)IpMKVPxj>r_F*pQ>sC-DmPaoJ1q;X_WIZfu@Kb^oV~%${Us z-&cW%QJ193ixruWJe@zbnauk81C%}wsEzJmIG5XjwB~K@<(*S?xGL2Lu7{LyN zAQ&A?5%J=O<6)%YJ@5Pa5Rw7pT%{OgFRSJ?^0HX8LRJ;Pl{cJPi8Tg z!42yc*DW#$Vf45?nHer?3=y6=l3A-17l7_K%rZ}y>I!-qZrx9 z=nr3r9k90)7+9UAJRbCT5K{>9c7a=hK?K=HP8c1enR)S>+uM-}X21muGHVsrG)Yws zP5q^1@7XgiJtMQN(Rz3x0JqIh2gt@l9yW5Qc zyyA$2`Dh6~O!*5lXg(T-+{FucuvGvE)=5OsTbKc3pu;2{*3bv2%nJ(0UL9Q5h(3mD z*n5JsGQK^BNjb@F3$Ga0N_WYmD}bD;gd_wmRO8xu^Z*hXs$!;Q>hruD=Esj8efpPv z1;EFC`V+Or!M%-rEl80T9Bi#obV^cHOriTAt4t2vl^A38hXl<<2OkT&+w4QZm_kmo z4heu6df(s6HWs$r-G}#r=guf+kK9`BS^y%F#lIk$Hbs)_7H&`jkhMyS9I2Qc6pF%x zs@x)?hajP;3RCgo(>zb}^xpTs@8ci)Spa|RJO0>5Kl+iP9*NeeKnoDkI!AMtL7_)>b%Uy!}1UQ-ai>X z?>+B-$LHR9QbgB4Z#3ZA;VNTR^98S36_X*!VzQC7NL3U?5aSmlfSUM&|HhE_4IjkO z4V|hKm#w9bIj`iX60dDk!m(olxjz^qy=#l!cYIRoWYY8nYi(@CY>{)7;uJ-3v>wG! zoYf#gQ;^XjhyVjZQ>vma^I=(Df93X9fBE0MO)Jyy+;~}xej6eg=WUy&^7P48)iSuu za=vD76xB{?7kX8NM35o|wFw3U(SzoS#I}VObrT5O_JvXe38+esp;N?AR;YlIY8>t} z=HrtuOkCH91i<2=x~rf}I2S~Ywx1*sf$JJ1>xBJoC+IzajD*=3BMg%BB-d*|5|YV8 z(A_}3@Kry(^2&=;w7y;7rIfeswqtShSgJ-m7`joi36$rB?1v>Jug>^!VPmB>pT=W85DFETLdEO z7A@F%Op`=Jb!j~_uv^g$Z+m2mT&gg}?LHtWNtFr!Oi`_F-~WI9t&xZC`<@@VIYqF$ z`Q5WTRnjG`179a5^=T$-^XDM?{L~ zwUK?O<7ErFi6lyqA~F@M0WaEv+ZG$KEXHIp*&b3s(p^dPNcW)+k!lE1L7gC=o486( zFmZp)wG)EsaD@q(D9S@&7!R|mVcjyx%f@ZMAefnqo*kGAKu!g%X9p+cagyh2L<_Sl zO4Typ4CXe?)7!8l{f>{98{yj!f9y|w*H8X~zkNeKwOkvQV%LtTpaq5{MKasA+vk92 z;8fHNMwu&;42l&Q9OE(0FgQ@Xk9&`_jq2LlPHJYbt!XZ`s2fCZ*-``w9OvDk!d&(i zBsos^GQ4~HU_7#xof>JbV7enCA4F87Fd~z&cDZhS)Qrd!7qgwsVeW4FH-GT&yhw$* zY>db5Po0;D*_ADqifhXZlwz&ra4P};2&x`TT>;>BfhdEr2Ha#w9)~PUAX~8Yfv+4m z0<;Uwgv7R{2#QN_sgBDvgDfU4eDzia%XBzkC>Tm5d~{(mFI$SD82qr0<3{GPNNc%m z;eb~dxNg}aN|C4c+vu3?ZA3wFH8(FlFY^~a6`B35^Yxvl(^Ka;>xi(gprOM>e zA}@`_rT2X8Bnq^|an@}M74{&7UKoHN*DXo7V{*D-Z4}5nOYdxrk#u7*_MYq3tLtZ< zZX#(uxTDaK3e!^j@#8O?jsDgT{IJ&S$i?)mydoc0jg?-sDL!|{symXicj^0e9)|*j z1jH0a6)!vsmq~jkGX%oSA_A537UP0=xzb&?o^uh1^v=r~Q_(|}>LSAXHASJo?K~7p ztVJVsy?rLt*^?Ooj!QO7^5!_kdSM1t>HPs!Z&b~7?e(CS)M6@cFDQu?DE+s5ejpOL`JBp01Ajkt-3nBux+F&oEx&WxvM9{7YV%>N=ni5F5K#H6Lcb5)9&mlt;SKiL* zM{yN1*;)qq$};+{NaorJj9o1|(IPYHF3c>3n<_o?ZcBF*MJ6xTKFShqm|4^)bXJ@xQ`h^3#1O*q9d6B2rmI`*0*d*?Kd4$MB~Pm;k%B$x@? zacH|7P|0HZ5d4^nQ^n*+!8pCnb?5U#AGAIC*Ws-d00uPITQeY~oghIeT zmMYsC1EYmqSG^DNT-QF@lWIuDdfs}E>>)xClv$T$5><0MK6>Td?|$>=e*Ry+$is*K z=|7*R?e^xhUK%Oab3Yw?d(i%`TQ0Lb9KazDmIp(eAHm@vv1bXC%wib6wW3ggf;W@2 z0sW7h9Froz%a%Q|1<9d*-zi^KMT_)E-J7zxRITF#U_!7(R>yUVeM)6GVi2`Lly~Q* z%E(j$B+uuqx9D3}r3mY+%T&#@&eQFqNB`uP%%T8`R zT{*dodD=8gldeJEv8J30=BkrpG(>x(3VUV?Mp7hA2APw^NoJ22y+d=}-M6;(-nuGH zG0i&HTB=W{o12^C|MP=C{KcvG&hPvaKlcltdgXY0a<`etljrgHXhW6r{7L|&NHJs% z*$iaR4@~l*?`_~=vHNSxF0OPCnaR;FWDDL-ax5Y`sIxrUK<@GRH6rurC91*=W1kD5 zSJ{GPce=>xI8IUvrYbEG!t>ghxdwYs5UQgQpS5tA<^IxIW-`rj-P(2S>$L;vj%6}; zTjo07+`jSZqn8cBwC{wD8U30KXVT#rh$|S0C3!35D za#s-y`P~+4%LheOUN61Q(tDO7qc7MqcZ=~zB9Z-i?b(CLa#SIfqaSZ3QtCY2JbwJ6 z|Mczz0_saZl z-r6ED7ww&{czVg3MT;T$1@+!I790=STAE2F*DYM78phbjDBF%-UJou6W|&-#lb&XI zevYl>rBMMO9ZawqYzXI*P?nLI%xgvnMyO8n!J=={62#G-V=^!*gp4 zeD=HNTSR1pIYHdsl(|k~y4*f`|C?`o`j>w7i}Ub{KmV_+T<2O|pY8K^dD;m{%urn(ANAVv?h;$%kWUyn z??<0uc9<}TU~#m_EwTjxu04AWrZ{_24XtO!KC`MyBCDfC3=-QA_9Xk=-L`GfqpPF{ zUb!u$6mz?I{OY&-zTfwWkNxa#`|9&DenY(62;ZLg*hfFL)NPsPx8AxO=W>7UOI25N zVyY@&4`%E`YpTNJa?s>X|5An9u4^_M<83e<=kXo=tl-vSo@AN?g5J|zdh)X7E~*Pg z=G}b^;Qi1$n_}&hBI-L%v-hl%)FOi~mYJmhNZ7zqA<4*8O)&XJcV1D87RSM9_LpMQ#p?LB^@liOV%h6_Ty9C7+*nQ;qRgEx5FVi#d8S zGOyP#!!m2n6vehhDNuzN@!(BPU^E3)a&5s(HF&{%u+y=qn3ZyT<+b;}=UqSlMK|LS z-}cA9?NdMdiDLfiPp__WS#xsffm%gXisIQhw!S;b*CLUqF7BcVcbSU_xV7AZ0cNC* zekwVa!I2plopiy?LCd)D7({X1FP&(?mU$Tmpdk$arXrV~DS*j<{M?=U+Vj!DT4aLT zmh&X499*<*m}Mv;V`wPX)}sZ;Y0>$hk8c(cv*NG5@s6MP@sIt+56E(g&p$h#ihuUW zHi!YPxOUtuI*gN_T{2=PNz9YBpc&l6T-@YPMZn7zTdl?aXMwRc=s#w zThCesP1u69>@3LZbqAn{iuvv$AwpFtWr*u`9<&u9F$BU>kpcW2@;@({IficFj!`nL z75C?UjRX>g`KW`hHqYuxLl)zpYz;ivawi;NV* zm|ve}tJMzEoNDv!E5G+Y`R1SbatGddzPj4c_4$1ySrl8~u&4s9=Kw{Hc98pkv(i9w zovIorf?~2o78d{mlXIv8E5a5z;E=7SndnG`U@n*^xomNc45k&ENG>Ow&&3Q{nn-vBYhGd|ugX(or+5Mer|uIMJU2qPgl%{nTE zYl~4oA3jL~D`Seuu~Y&1e2X%M*-9wN#^P-d(r0#qp%7I4t_w>xUkCc>MTxz2{w@{>5MUZCGhu#%~=j1@&)R zeD-to`Q^Ma)@>#G8Ue}35XoXR<8Xo#$&5Ih1TqL90qi%h%$z1MVP*iit^K<8;!Nhc zg&KxHJ0f}yL%L*pfXL+5%~%QrDMB?y>)C@$K^9FxB-tbGpRMb)-92AZ=oN0m8!4l8 zFd}gJBpP$8-Ua8&0qiCzx8EP@n`(NMADEEF)whZ84!^X!6D&@sX&;mhX}#EyEL=CqzOqNP1$>FJq$Tn_K4m?nCrQ_ zaw-GOMR!C`_6~#z7f;Eqj;+UfZP&Fwd%m>@H6H8Glm{~ukr9zWL`Ekgne$|2QjmwE zsUVxqhiY|x$L--adn!KgyMOoR@9s`VjqGHq7tzVY{d**yHf z_x|7JdExrz<3b77IIn#aSD)Rt)}t6rGBV~dk&BoM4+k;HzO@8J63XgC##?t=ak}#9 zeN!YDTjpi$OT_?1Tw5Sx(iFtjBO}%=Tym*cCX7^+f@ocst~?kQO?O0Qb+*1$~0^C9F{a@Vul2_pV69S$-~rdtTi)HZNY1lPPL(u=C@)(l^K@fGZd->8o8Dna zw7a=xB!I)wN>MYJ4hJdoH+dWTgqaXQ%%h}uuc%1EXPkSv2vX~5O^7EP` z<_Rk3!O5{4OorLLP=sYiz;HCHR7m3axmTB^>^?*!TVzqX?=aHQQ=F;{GRfmTEXOCL@81Wu05;f>1dR^UVCysoeUhcyNJqm>E^O5HdmV_t;?z2 zzWNhC@rmE;k@)prJ1g#~GMl`5b{9N

V2D2K=LmO=H(3f%FZF${dU8AT}g*kR-U69OY_ib(2lf~G# zC{^YPN*X=+iI6MyDy6@HH zW>VQLHj||5uA|*rLK(@ah#R)f>l*8t#h_#@It-dd&*J{t)|U5|FvaE4-DRqx!ee32 z98AP(??9UF!>1zq7*`~3j=Id{G#_l9-+af{edgtu%-a_)H^R3wuG^ID`J>Zxe`&>K z-BJ}UxWB~kd111+jFm`>n9v-Iy;o;rFjA>wH79$|sSeQ;$G+HFoEFs~@*7wUA!K)+ z=v#`gR4E1KVy+b2U;FdBes}KC^X4dS%m`61LXnqiH)k-%1Ryga(~6AJrKz|n2@{-d z$~3ttA=B-<-ut8f=*tuXU&MF)4}bn6AO6szQ{6fbv)-M1Buw$vv%btSS6N%SNu5-L zP?)k*9e^tk{y+~=u$T~iD`TV|Nn0&Ml;b72N*-et&l#x&G) zzy1oTc>f1p{k6}2{4td{1v*%4@X{DP)ZjZhoaC6| zK_sVwJrx5F)MIi~7mif8kg19gB)P81%u+B<@FLZZ zb5YgTU#*{iwhcYQ^GnP{=86_{m-EV-qn_71jCOc(YcUn^eKeYp*>_V(%vB!v*ZbK> zz`3X}M+%s@_%_FDZTQfkQ7jr6h@Edcia8_c6(GJ&-eXw5-68hd&ICmQpu^vma%Q!T?WEiU8AL% zGC3MocTd*WUtgx;DG8bDvV8NmeA6dB`RT8ahoAZA&lW$c>*Kj}rkWfMet&Mai;ZSX z0#IDnJf0k*DcE9dc^S(ec1mQeqM(q~FQlefCtMGU9nYs90QT8iD>x7$TW^|~0`<@q%ZN2^t<<9z8`&&!&J zDm^*4cgrNzg-JIIp<$9eNzxVfYZTpQP*qrqm~x+F$jLN{)x*JWY4iRZvcu|t2$hP+PzIiC7ZmC{hd-vD>{lD{%zj7-6 z^ndf`KJlrKit$wIWoxhAPNH(Y_QwZ%c8*9MCw12?^SIbDYbGz(h-4&Y$7RciEQ&+b z!>kcuD#gVVk?fHKRB&nO4-O$9Yk?`oZ@IVeoWP5yaBK0_^KJN%{ray|2*r{OaMcbR7EJu`-*kqYvB?xmpUfGkVw49bC!Cb^F= zOl8L?Ymp#hHx!~8A~Je_7@v7_R7ZlXXPLzwgyFr17)@A==0HY(nXz8`G+A3C2{BPn zf!4COeB&KU&n(qWhnvHj@B91z?+1U&RQ%6><*)qskNgOYx67=?`};P{)_X+a?%W?8 zRTamB4ga=Lzv`W}YG&Tu_tQa(LIF4Q2kQVEp6N_4LUJk?e&kjph`_)JjA7JlEkX9o zZ3{EZJ^F&CJCq&oVzwhXgGlSmFIUC&&%5W(U!>+Y&Raw_VsJ$QTYWmYXVPqQqKzU@!_*$@5LZ}C+8+$TRhFW1;| zjXs+X8%T4%wm2R9x&?%XN#`nUAkeCe37TTKtPzo?Sw^u`Ux0Z@1tUilT_Bho)euP? zX7@5W-ZYazIUnv5+ZLI_8ze<|?Ku~?(-d19-9d<^f@?(UahRm_Fr%8ZNL5TlC$}x~ z(PCaj)NUWYy1e?XpZee@|1Fk`m+{*WFE_%sKmO}K_oqMgv5zj3smRT3g$Pt!d08_v zi_1I>OyV#NkYu`Hy^eAmmsy7&g4>Qb%*>^JK_TBG*Pd_@$JSzNdA-E-8l_-a^mtG_ z47~t3@S4}Pmr1>dB8TNfb&4=S5zez7C%v{f-BtkCYs^Pu&{RqhH%vtzJ(?TCb&~n? zN5B0$KK#L-`YrSDp@00rH{SHivuiC1U_Q8t&~!kzlT_JxC0h#>s6uwqO`34s^0;Wk z-ttk|Z4!=EMm0E@NnTpeMICF)wZ;7Io6)n zo_Cjie~sceEp}Q|6|Kc621F8y^A9w^Yn&4rwExENg%o>nM zxV4?^(-zVRiOLCC`lgc@b%=F`@Hl_gBDpMuPvWn`uQ4WIL>yM z;Er{R9x1{=QgG?{=wwsfeM?%;YH*`~bKzv%GOt@JjwB*-96AP@`|fUg-#d@$QY>l5 zKluB<^;2K5Sn@Ky2JvzueEZ{*pZxSx&QMG$J+cg*p~*a{DkCYR8%(&hVS~<6Wzu1{ zCT~62rYfW1G4``%)-A_Q5D^^u`r+6xa(L(0f5Q)c|KIs4(f|N=_vU^f z(gDImX)0T!kY130kz*)y5a2{mU1sA{WSQi%pI?u&jDSrtS^ zQYD8ZPK8x4Qt`QG+iBJw#6EtN=F*a?=n+9qzSlw{nB*YEtZRZWyj-Ja z_6UG$>w~$vZv9X(@U(M*>Ry1Y2lwJz+nwl@s8!t|#5>+NHuTw#_0@NMRJ@GezIeG2{znmOEG8Ff&SEWDii+y_ zvMG^ZL{SAc`+{%k>*HHBFz9`Dso=C8`Ri( zRKwuN++BK$9LDJ5qSJzF8&_HW|ITcp`@{ZRRbL|l~r_&qn{XKv42Y&dse*X{gQy=>2Z~De}J%9G(>3w_k zP_7}&m?vF(&dQctlahHlxw$ZNOpaOx0aeV7`!xX8B9}F)L%{Qv&o4c4H(yuf)}jTk z52+aKz2b7+x(Jn_l7}jjadA{f7ak|ww#}8Mbj|9LOi`?zk-WRc-i-uE-k$0*$=34y z@3~1bsXpI++jst{pZtlBeD$gL_0NTr%UtdA&$ri)p2yfjOQ&|WGQmK_Ucf<{T9zJJ1371eY+Q_7~Z_5EJfDVg;WMJj}s>2p|Cnq zIT_Zqspjkuuo@ugCOx_KOcemz+C_!Qn`4z4EEAh(udhNUM1It&JVASJ=#0@4NB7Ndz0nIhOSGjpzLF0JKI zVb`KP**aU#PKbzzK&g=BSj^}u^Km&}ugg?eAAjm!Jo$G>#RuMtXP;26U@SPqfIpHDFRr zThE@nJybKEj#UK9R6c)yeti4*>wedN`eXm_C%=lf{-t5%-)KrUd330B6$%7TKYzVl zYNO1P2c@qODfgWS*|yBY7V@sgrKk|Ntm!IhA|gpp#7%`fZ|SQ!VFQ-+1NC-}|k9 z^asB0@BTZa;${2?kC!*X|5)PVKlAhNe*dF(zC1s#N7I&Y0~E2frHDJMNc4=gliXTF zL?*W_E|*>$QxP(Uc`TH*Xf4tr395?}QKc|jrufb*cFWeH^_YtEKH&Y484(E~kYkS= z6PaqF3W`L}OkUPhmud1^WvVvKB{GhODc#j9BH%aQ{0INgr+)TJDPmtuJb4DU^Jyt> zJzG!38mS^$4yWaA zy-w9-diCR<{ME1GeSewgaUh;g#jac4Ebi6Z)F-*STLHpwdsEHOdOUfynM*O4a^2!{ z&$<}|G{aJ*XO2`9lSC5KqUJKV1TC`^yhz2m^@x15=(fdhksZhaQwn3Q7~}y05SU_1 zZY{UYEg+DAtuc{#wq^0?{ngvU)?=Oy^_}1N;jgYs`WxdrzVkbN<^N;v&EG7&iZj88 zIOlxJy?HZJRjLvy?Fb=2NLWH335-A>+6c^IY`|bPFDwR3x4UPa?mwaDmzkdFcF)pJ zKhu8NGvjfO-D3~qm1Y}^0kIeaT9HaBsY+FuS-IYOzvY}0F+ZGdy_s66sx09fPbziu z*3FyWiF>|yBi@J;as0uoa7L@eK@>-dMUqsV-YjB+WN0`vCPEg@3U3TX3XB5pd3D=z zXcM6^HV~#K#t~@(1^^TlQ7FJ>&sI2!C{hq>Q6NR>Jo5#qDy>5l5RbrhhaI0rqN%Dx zV-c;;3xpn|jv+S007dB+(?}64j3N;p4dS)Qcr>`+$kng>^FRCA^HarK&bZ8h@H~?B z4X^cdA&s_n%7Ia$AU28>*xU*T5H2jm%7F9UIVO!!I419TJaMJMo2QTn{}+hc1CBBBXB$rOq}UWNip*~uJf z7z_;%C`1ADo|D*sQIXM3iYQ4BUvceU|IN3bw<=1PitMDZDy=M}Mn@DGr3{XDO09tm zCaI2+aAbpv(kBLt21T+tcHVoVfe0c4EW#wL1Qn8!Pz_XA#~_1&V$aU|>7=yQIp&3d ziVXrYvmck%Gv}7K#x{wO1rm(_Vl;_VRhk5{IdM9|;Xo^eu_0r$cYa|Ii&jc&VHUmk zhP&SV{qOwnd8^{1pZfFzKmK-EI7KuZm?%=#ay-z}+!>9400>%R90MZexs5aoVo+MP zraln4sDdh32tWy_Fx5mnNLD(JvM|)vv2%W!mCkv`yfjpXK!ln7#99E!oge2miO@P8 zXkw8lA^}jEoMVNsl{sxFO>`VnY-nL265&Cj<3TdDMG|W>I(+XBpO0e{&xcrht z#BWXVL1NNaBS2R8g9j4F!pwwHI?v3cLRm2*$zp;=!?^IV21SAzwFU+e0#E=1p|r^h zXVwG3!cdpimDZP~bKX0V<)NZ*76~}Bj)k2_VO^}jd5#HL#6$#uf@qx=k&UU3V?v_P z*E=9I2`rD&!h2(e3zxm(+h2PQ{F2ET>WXm7gTbJ% z))CUeATpZr+>MqZ76{>;_w1Z=&XYny(Mkpp4ijYHaBebp%ut;V69}V`B#JOj2oVq^ zbel^e92gu#pb5P9tdJ2sGZB`KLq(!i7-?igFEGhH0OXFxg;N@nM3F{~NJ@F;IMNjB z*ci(>nT6|K_3A(T-@owF=;8Z!|L~@pU%s_@YCI{UNT;y|fGqdROHoKZkwO+O3hUTA z&*7Be(7-~10&ENl$fWd)VPFLV2q^&KB*r+Q5c4_j5F|0U5aGapCUDF^Sh9FwX4#ln z=Vh3vNTDV~LIB7tTgRp2?ZOkmXu$wMq!19j_X~rVwTg@u&k$Yk;7>Mw$}O?6N!ML- zK~|I-JK4eI1?L?KWVwwDMp_XOB6{x;*ozN?AP{93!7xSu4()_?a;r3kmJ~>W3Xmj@ zF^bSAbl#WF8wG}7F$#xFgaJgsv~d-K%b`6Y88Jny9NsiKKdm~|n%Oi_Mk_@WCJY&aq`+A(%#K+T7=s9smu{NbI3Z(@nWY}E>b!H#d(Y!> z;hgu*8I-yNR6xKxKPg;fhzPW%#RX*yDZ-MWuoG_pKQ zN}osZ@TzNn?l1oG3^b5@{PE3~Ts3swZ*6CzQHscjnCH%U)|x;d%Y70ltspNP2s`I3 zGook(%ziSpM3APW6oy?9&XShadGE8rWm##hNA?j_s=)e0%}(wHvC^7Q;nGmW5h+5C zu#-CrUIC4*&%M_OX=;=LgBZnHSd3D7ppz(?W>cLWJo?!9Oza4Fa@D=!rOSC)oLbwt z`0(N+FOt}lh0Agm$2!YO??G!SO20jI2vXQ;h-Nqro0o1lP)VWyLzzq{jp5RIVcy)y zopshaEu1QeG$H_sSm&*i!ucdpaikb=DOG8#j6x>d$zASQA#Rs$>KG9gh8j>}t+Y{| zd5}bGNRSh)^yrcYethzbsA4W>Q072*K1$&SN>3C)S;*pIES|I6h56>BD9@Zyq!sLJ zmqb_=VSs$-Z_Mm`I#6MXg|*eOW)^Xlz4IiZ5Hy1KoLN7~eOCIc|8ynolgq^FQ_1i6f^2b4Tq6NBn4@r1r%vmSV%m(bdX$p z)z5wLi{Cj@dRRFvS6!X}z}o4Ziw-Skd115?mZJ2=Xd);>cTi1*Wkd)Ql&XGb!lRVJ zq~*NyUYNr1c`wd+_FkhH6cCvdZhc&4mUGLKl8e$06AFX9oM%BOOD;p_0Tk=Rffxes zAc~bHiWHIpg+$uu1eX>D&SpA3@aVDWnbHFQoLq4?y!_C#oSt0Sx%R~ut#4+EP$O9D zqgY2Vm4){V#trqe}<-JEFtx*I}h57Kpo|z@Ip<&M}B#aj1<(KyhA#(0N8g0#pd060$sVGtWaWgv+oFG2>Emllkatd<^r>`bCykmD!In{PNW zDJK2Ar)mHIAOJ~3K~#@DzJ9~YFCI_rU|=HeLnW6n%4mopViu(-G88!EVXD%Ia>4D~ zJC-C?NvuK(P^H3HN;U*WAtEY`X`+px$WR*5Fj0y?5#-h@h1Llo0!nCCqZB4aE2ZN^ z#gU1C$shokSdoE42bUu#qQ%SZyLWaJ^IXmonFHbZE4fS4)FSxF*d4iKc{(kJ3$e`# z5HOL7Vx<%S0stCACL&Oz2u34gG>Rf2L=j^MKvdvB1pomFl~D-7EJ><^`O6FE81jNi zVQD>kHW7&z5K#(+L0BBK)}#|0L|TMVk@J!)m`g8On3i_o@XNpct><$>;MvHeND`A< zTRIPiE?jU9s75NCdq10H75T5qq|!8xAxXSctTMS6YLjrR5=!KQJ0z`Ezgk z!k>NRZ0KQa9p3TY_pLs8@8ieUk6e6V5S`o1A4trd#%AfSW^zf zl<3%?i4+-P$B`xgK|)O^0sw#nCJGZQAW5{*s1;i09Ya=fVZ||TZ03p0RnLI5O#QAA6N3&J@ZxbEJ+-+T1RT+RoX1L1is z(;|M!HAh^Tt*mUm35`(@>f%|nCS%At-rC4@q==9O2tlh*WKRxZIE-|pj8d8uD2#_@G>R7&Vo`c@ z>5X6d^4YC|%UybKSuxo4)03-Td|_U2I*h2aD%PV^CmLDA7-9kOQkFhVG${<{0mJi3 zllS7h09NnGEI@#SS`&K-X;iHhAZ%@yMd?P1aZt6w(3%GX(TWU*k%=iW#sdqeIL1Q< z7AM6x9Ui{>-tnHphtHJ!=!f@jkE5$DF;AR4%^sH)V?i|T(fK%1Ea)AxhyX4uL`EYLIWLX{s!l~v9Tr5?nyh1MeYjZwkQD4>)@X_%5*8GR z42G#E)_DR*2Fhrqm6(XoXi{=;v;fL29l7cI-*|3qCFXLDWe$YryPRCfe&siQBoNPuAw(=nZ#0=$rHM8XI>%a*2-wnt2x-!W zw5CX-QV0M_lhGt1d0xh;Q3^>DgLp59Qdrip9*$BZiZl&U!O=%gUw+v^W{!rjCdf-su^uEkj+D|!3KIp9AwmR%IM$J&bfC-9 zD?+V94oOI%))W~P85~5!07w``I?@p0o+#3YK#D@`d}NRbhl6M^h_!}TX;R=F#3@~U zz;FX=0d#2t~vwiVPwV6D%%7>A=KB zM?@At1cyuUl}8pW+vM=8zIXSTDVTbCdHmS=bTat)8xK5oY9pJL0yG$XR?dP_<%;(-GT!x%`XuY2pS{n>x|>vN!rx%@OT?=16zk;^YE zh+MhjUjDKp+uONOSQgef4!s{q(PUC)x%Y)LMk!4|7$=6Ar&B8cw)9F75=61VP+;zv zy;$qZ+&U*(E2F7u5vdRn1VBY5iVY(o`-MbV0W^vtb@;#quH44tqOX7VnP(}Sae4XW zZe?w2Xp+U{K@w}Ru5>=nowqI>L|N{N(wC)+5J)S}pkoaX;7#(}A|eqcsUbpUah8R} zS}sagWX^jT4h4@nHBLI$7*O)VLgztB6;Zn zAj_G$_EK0bN++JfHXuZ0loxTYH!9Da%$Kdvq<*#)}LW5~I<38IP?-R2rE@5t)dF zi5d+IvrIE*3-1cA0JOp=49W!&0rBFT7XTCKBsHWcO#B%Pjn;%($4R7PgCrWQF;IF? zNiBX{wXZI8s0nrl}^QhQl-+#Ha|^ zjS?b-tQ19b=z=9pmf{0ny?gb+2lpWZ^vENpwszvzzxv`6r#CmYcEpOHS{TNpaCIY7 z0I4BBvCe~{SYaA#@jjat;y8&=0VIY@7*Hf2EYA7DI;8_DC?Y_@NKqPVB6J8#i-Xb9 z5D7KO(olIo)M{xtIdW)m?DFM{uD|=ckDq%z0Kfx}j(_P_KZ@BSD_hylI1|gHbfV$$ zQ{&+vUWgR}7nZH}!lD5Z4YqXRe5}wYj5Q^iq$)WU=Q%4K5|Sbc)zJV-p+Zn7fEW#; z!5~>!9uh&MX^>DU2wE;VFe=3!SR7n-&Fx?R>W}tC6?1tWGLHyfcyjyA2TrfAtQ_CI z_`+q+a`^C~EsFK^$#}b5NHqc%PQ3F`q=5wyopas`11t;-doc=$@Z{+{O0+fvfPab(}YkhKPc~KA- zN6G5yRyK7D!+0U4X>Lo;p(a8hSTEN3((>Za2uq|DA)Hvxlhi0pVUl}kSy;3pW6+C; zK$^zd7|))tP@qc2;b=jFdeKEg@99h5*@x(7PkHle()%7+nU0I)g%rtXl2fbOhnG@{ zqKJ5$+rqI%R0PgLVZF0nAt=H@tPt_UdNvrwN)rlL>m3VwQG`jXO6LIxkI1v;yoIpBEy~oZ^jHPHclu?lZ7}2RH#%O z3C9P&`px}u`JYDK{F=o_j-A@xoL;aPix>hS@so+Y=+J^FWt|TVqfvxekgzO#nOn~? zEu1iFMM-L+h)_fsB}h)dmX4UosM5ML0j2b4xM+d7lq;{eXnSXS;gTEw^3VTvzn9*V zx4iYH)yKZMzFF>U<;$al8S>0V3X@2iI08j19Qv(z&&KF1v$n94%$8n+F^W{08m%cb z)$@QJ$a<#)jH1$dQZ9{*115|wIJl%hC8mth!(aNl=h;d1?8)2TaPWH%K3HU!<@U&- z(Z-fNIEp8eEHQ>nWE2#o6_!v?ZLQCyc4H@3T7h5^n>f*0p(3od4iSSF&x0gEMb=uS ztP--GbfPc1@W9eAe)9CG(FNDu{p~Y3_3RtBijK~m(UNSOA8-a%eC=Qy-c)kYxzDvXV>&LUE2i-nXx z=>tm_6lH;=mX}Aq+@j>*|M#u)`e58`x4*)z-}mUL)7zVNkm$vQlu#Khr#B{X97WoA zFNhFYE@ZjSb4Q3osFc#0AhhHrV$Xt7luku{l$b$koQo(iVBzA!Lk7s>tG@lU=ig3t zF8eNXAp9ATU%2hy1CKoFbMcnbSdSKyqHtQraRk7;wVeTh(JCCUU=c(hs@iadL8I3D zbTEkHWH3mC%QQ_#2FJeq;qLZ* z5OpXEQX1Kd2(b6gbCz2{84S`mP9viihQ?aAv^*kPmdW8S|LwV`ggjI7mfH?*Y@S?M z-_9nUJuHqQLPbbQhk1daF*N{yGE{Y4^PJ^Q0H;|&S_WyHrh}!0K@w>ecAgI}r#n^_ z4!`m*|NI;Ky}sulciuMGnPew7v$fM(>}7F~YNcbNM8c$N06%@k0+kQkLKgpXZ(s zv>~GjQ4wM|P8fQSF$fSvNtzA@!$d1ZiBXI)GHRpDzH;}OZwPWO1v5t*KMCZaRLh&p}K$?kYRY zOu=sM>}*VmopHv_krJadJ8+&sh(!QJ8Kt8*GLca#j^f3EDQ#gbFD@=9v7#fjeC-#{ zMC;Ujlv{67hZdHOKDn|rb&5c1+8$>VepitjPb`4Tay!Y(k{y!LDvF~xjrG7_qO>?(b2%(t_q8wH zz28@TR^;|OUtOO5{-Ja!O7!+*GPO{8aLx&fCK?W+G}4iXfLO#Sk1o9Im4EU_f3e?J zeOBZRw_h{#Pl6*IQSN-dvWr;CFxb)ao>!mezV(eZ=&iT-t)fhb-Mn?`0{^-B`SNnZ+=Tz?c#OJoR^D=kd zGk_40iS%G0e({UqfA=r{yZyepxtw*G1L4o6-1>_jovu%8R{GMhW$|3i78MWx06_pi z3=PIm5gDap9SxJE7cGA6kN*9BU;Y`BU-`%X)-dAr%!I>liU@~ThA^Gr;;#iJ_sTJVo(Jcr6U~= zqS3+8_rCBS_xIxGayDcRgg-m-ruYBW`V$+)PVRHdHjLpB;V_C-s%E1gz2Cv=3oArK z)TAP%Q~StQx71M$)8W z9S`Ht!O=Z`^N0Jqq~|Nw-1&jcwVixg*usZh!M?vG8f5^~08o9eU_hfXWMY$!l0z?A z{?QlyxBXqw^OJXf=JOB!_{r(!q|B@@ym!Gn3|pdAMQ{@(aGZA@MQv-d*TjTDFianSIx6ZQqCpjD zJ%|Pe7k=>N|FmDLdrorOdw+f9@zeQs?(*R23-?t~Az-5bssC5E;SQ5nLx6|`M1Y!< zAsy>@Azpsb@(=#<|JbL+JvVvTFMM$AI6u-w!B_lSB<7 zre?U9UUJ2u@BPW|@6XzvqrBox?;D>Um($W!u7C(Pst{@Ki>@kW^Z*C|1c-nNNFixb zkus?nEDx@{_Q)6i!_N+L@DEewK==ZdTi@}K?c~_hX^YEU&!d{oAYC#iaCw_f~@47lyhR5Gqyl zqo2JDU-h6tL?l3}ZC^~$AQ~PVJ@mK#_kOJMS;=L$y=QBETu!YkYFEI6NWCjME>R^N z$Dnzt_6(#^MT>|Ulp!6fWFbCqc=?g9{PDS4+jEgSKJuw!_dhw^oZ8&^lDl3J)Vrbq zzs4i#OBW8?je%6}3XRH;PINL#4qkHb`+xp|jFsmy2f`PsyzUo2y79z%xl=))cxdcC z^zZQI-tOG$&BK|%-uT9(rC;XFu%b$ZOf95Nz1v8Wc$|Oro#h@WP8Pc=*fb5gfktGFC7h3l&LiI33cIcF*$Vkq3?a+56;Od=W-@x4umf-dE>AA z#_CU2ik-sebrcxv-7NlL`#XKp--&{xi;~hB!GVQ4?zr;z{^h?u zCo6tRx$$iuI{o;1J}z7y?7lEps^|uS9fS`*>d4ppI0$5G`G_ zeE-+}^VwhPGsu;1c<=hDtzuldlD(~?Va6{03E-@ee>x24DMYZ@8-Q(e2pFQnL=8sC zi!MKO|6l!|XK|6wLO%P?KlfK(J~mmOlvC$R_Kw8^_qW819(ISr9hv3O8|MHk?nH0~ z4pW^jrI%iFBq!moGW^y}#KX!}p%g{LT-*b#%Is*{o*0_J{&;Ps6?k z4LD04_rKSCX$1hm_NmJ7nM5Z`>7_3{^36ZqpM=?~-}|vgAAEAU6>@>Xt_p}ju-+AY zuc%&4_-~dn@4TX;nN|snpA;|v2q>r`qA1m)0}HRc?V2zA+xpj{8IB>+H4t0 zFnr3OiYXpOi-(sV`o_67e3#w!u8ozQVq#q};~3SeZXpoyDYVcP*|kAt*@7-#iqi1s zq(B+eiAqPw;Y%<4$(PP4Q~H5_{Q0}T{_teI;X)y_&Fkz6?2rJxTVxNF$exe(aFVd) zOM|B)$+Spb1 zBVc<3p#CC2L_{P+M67;5tX>a*SbysvX#1eKfCgGZ!C^Rb#g2VZo;<$slGogN;-Pai zcjlVczH8&eX0cP++;;S`z^=q*k6(ay*{Z#J-;Y202_43{C($xb(6DHM;gD{9^ z?|hjRhpv42Ywx=Ak-z`$Incu$AN%A)F5Fxh7h~rNW(&|o!D`vv{Sa1wvtJ!0K<~vp zg{J2ubLKZ4*a@<9uIRQl5wW&>?E`?u+3oR*(pFvwi!ihG#W=hC z`kPKYdf!>q!!P{$r@b5+pPrOc=L%*AouU}5A+WJl-AD+r?<8~;(!9RvFo3&EUe6Bp z_~$n5#3G)ZwHv3mUwZ57o_z40v#N^g-|?Xb?s;Oek(HVErHBiq!p)X|J@v3B6WFo; zH2^>Zm_3DH@2xryS`R6B2Exvlg`!v%CD_(W;>REFOu71;dk3X`SZ5K9YwhbM+Cki$f-+a)!^w7qI^@}_4 zP)7;a+YZuU;M<3RjRX;4&$h5@t6ML7{p(LXaJJlnYi@bx=83IhTn1)1RLP2nYV7!&CSK4VM~1iGoq zzjd91uCLU6gIZ=(!Qwqncc$0edfUoFKR)BCc*$#iaeHN4POUH5hq@RBklnjth8b`5 zv8QLy!NB@qqdshP+r3G4M~7`fF|;*gVduBj$2Yz8&5z#m{WGqLx%~7p2g37F-uj{6 zdi+Pni_O9np6hD(J{<}Wunj7XGjxOL03KB%MiD7IMxX{YyWt@05d+MApB0qwpR~y` zVfLlF_?lOqKBFwq&2RtE$wyZ5?b24IG0g#qT`qsk_jX)_r?YoWG+67SPM5Y(VZ)Qn zn*Ke?3Z-t|R>ecbW!K-d_SgewP!(6b;XSLzH}Y{?8dGhFW@A9tQey*S&qftZgoN02 zAsXkPb&)zi+1nh_fJ4>NR>H8a=_I@6mRrv(7G8bxJ9gH_6-n-eeH{o2c1nbHvAfmB zJp+e(q)l5oz2g{l-fb_opy4Ds)Jb)F)HLbN*5sx;?|5vEh3B8lf$+SOJ3siFPyFaa zv6a`y&_GwzWS~Yo;tdkg;>zljA+N+wFbEZVLh08N(_KLNxlE9IP49`f(Lawl#vSaYNX{&7Bo#4`tPCP(T1- z?=F4W4XZzOzVP+${pgdAtY+JVE7&`3GC-X=z^?u3zUVPKdE06rN`NC`8^2;m7H}bLdAr@q;7*XglqOIxg7;@;C z_t^+&Hw3i7PrddIPtaz~`VTrrzoQ)NtD-21SKj`H6ZieJ`NEgp`p%uz@hl2TT?NxH zqD_TM3u4XwsBVO|v}{igsk<$n!b6$~kUL9n{x1T6(6+o6=IJE6^H<(}-?zX0Q>tPv zXHe!qczy}tMbnL`&m7k$LKX41C5F6Tm0Q&VJBs{+g+%RWU?*GSG@l9#~*n9$4hQ}=ZBs+x|;2j zp?9eGCKl{5qBZN+&HeUFe`Do$l@d1rV!I!(hpHXWo6!tlUnhHNBe0~LWyPCbC61r~ z03ZNKL_t)3=@%aQ?(;7gx$gG&Y@XUKCf1eg+eShtGfBaAPxltn^&PR@6*J^P@23`3 zdr@)ge6_^MQ!Ku(iI7G18yl026AwRcJ1%H} z@qF1ZCx<5+nGFs>n4l!Pxvvf#3SC3i3j`ahS1+0NN|)9ZL)ButK0bC(az-6}X_eE7 zl9}_YcT|(>cM}XIl+!5YCU!DkcL~S|1TiS-e2;H8`d8`TUFL`d9E@C!t+IL zd)u#WKe=TmmP_8FI;Or)YxL@+1{I>lPAo{Mh$2!EsYoe96%d9nF%;2I=f>aNgtFg- zYOirUGe7mPunGd4b2q)^O-Jwf`{$~P>u!I~_UcYKb@fS!U`hMdziX`;_q`MG5dzgG zNNT#cTR__+69Ky>uU&P|(08&zeM8@i24=Ca(d9HNHcveAT=f6|rMYOlnc2*R%Hb*& z?A!f@)9hkiFASpA`r}M!+nw6t3EjxEUp3MJzz%KNw0>aW%dUUb#^dpYiFmqo46WDSq99Soo6fGC`hh~nq)X4B_hRCHlI*EW9#(aW z*o_XwUva~YtB*eToK*3WH@gP+b8wrK~S|_5LH0^|e z{aT^f^OaqUm;r{KD!TrKAc*(=Wv{#SW>Kp_>;(sQp&x03o3w)L4apnn)7{@Qaj+NExDtsKLS}UJNim-7u&bN7FRV3O_;T z?%h4I24?T=neWX0>Kku9dGy(ysQbY0eCDBhPE5D*;P`jyAgU{?FL~C)_0m5b-@hh} zgW)4ZO%MQ00a0x~p=0wpg5mGB>VO#&zsIk18#h<22iW^p-SLKF_deTdkz0QG!^e-V zO?OIH@~+-7{j!!WaVtvWnjvMQy27A6yi-j#g0M%VX&}0*cX43>6_o(9^ z0L)-t|JzI!wI_{3IqNxL#hTmN4D3-WmaWLS$5@t`mEnBLbMHf6rrXH{DPy<5~LJj0;mjM z-$w0mMzC+i_Q1b>BB%|sn@AG@L9BBdC!TeNY;f^-E3>&{$5lt6R_|?H@9ot^)j{xpo>AsNxX<$8&wu9F{VVxS;YuGI|IR>(?qP{0$m!IGhH@ArMP!Hq;B_Oy zNU2!s1`Zp7v@Q~9Bfik17@M3+EmD_1*4$)|APp~RSkmr+3dCwq1AtiXS08_7xA%?@ zeDu_@^?XvgvYN99Gi9P}DM**~1MCr=y+E*nz`z@;Hi6o4|DnFxPWZB?^pS5iM%?@5 zQrpQYKlGBDZ$A0(GsnlTc(%zy^tL;zTN zAz#?FWOC7?eg_| zKv)^O8WA<2R-_eaLaj-w#uU~eWjDI*mk!O80Ktp_?3?&m{A|m5>Y=^}0&>^;-u9!X zwR#`;olie--;>jw+~(c~QncSVrkfq?<+B>4P+vg=0Sg=OQ!2OxZE)OZx5>E8EO!?} z*b9SZU)^qsFvF`2gBs_)848GA|DF%7o!H1Hr7L|kgSyTd$R1@=-NGO2@#KVE zMzlgiMVhGE8>-0~gncplA?}vu1LdqMObztnv}UE~Cl!mS*AZu#T6oLQLz;eN{7 zKk^%^kFA&EqDg*$K(CKzmEQ@pO%=*iQ5_NyDXdCk;<`X4B9&;JYLgnBXp0ogc3NROm1#5as2!-SXsvPsa+Tic4GgsAY9ue?vuL&`*7Go0!URoi-NV?Zdpo&Z+hpQ_kVZq zTETaH;x~^zvN|1?uJr6cxaoAhI~<&$LtE+95LFxkkg5SdQ*2Zct2EI@lP0V_>25Nt z^SJxm%-UN-tl*>bvF$;SwgXeB-W8iqJY~}Kb?^Sb=~LUqv|jR;Rc3UrLlV>} znyQP38!ogybX%(;id32yZAhsqY;SmA>Chfs=707P>_WkQP$=D}>#@d_HVBDO5LS-P zj}`8l%z<#<OZ zVsvaw5}VONdhnvf(ei*GbR?Dkuq!X4@?>n;9hRgoC>p z5E5!dMv*a;#Cmx#x#Y;=Xq2#*x=~>37*#}U`x*C77VWtmdZ+C7cmZ~N0whp`Nch%Y z`bYQP{k^An*SVZsnFHaz$Z<_|KoXWPV56S|>e{>3QK$=IsVNYx zfKVBu;#eQJVDQ<`z4LWJiW4It@j+_;CgsmT|GOKBWwX)r0?2yAM9d@0lGC2 zjnxZ{4?g&zyYBwRY^Lxt|MhR*bN{L7c5XvAHI~lV`I-;xpAc+oMEb|%p*NQq5HS== zX-#pgmq+ofufFP^eEzKmmJa>o;m7mBInP{IMm5*dJvY)RlnKsS$LGNgQg)GG4_>t; z2||#H3Qs?_M5qlJy#Z}3b?xH()!@o7^5cfR#$#D>7u$mr7;VD2wd{^ zUv2ID_0HDmiS^!v9*x1U$jm{k_Cco(zb+B4zMA99(8GYPx$YzxrJml-&X-xSzOuPn z74Q7`$0ysFD_j+v)>X3rz(fEY4RlzswssO{ufOxJZ3#%w?O*=YcfR?>#~*$4R8czT znYk0}w!e!Ze(e_4cJW~Ld3*{ou*tO6qZpWlJ^Rw-J?uM;{SB{h{sl{sELz4Mi?KK9kWyJwQS(zEYtzI(Q^o?VGmDAUQ_ zb~nRQv4Ra>+E!gL2s1mjg&l8=@A~zR>{iA4%66HR-i8lJIvxnnjL)&>27t~d)cq%D zKfX#|0@G>n%`YGO>py#Nb31n|;g0P3dDzuI_1?4H54-+ycPG@;JM{D*A_DBiIktt} zUf=%YKl}7>B5O5WH25e<7q9#j^ zcJGR<&55@zfKsSn4PC^LJ&@|Dc9-K)M@ra*z*b{W=_i2m&eT5m$m(NHY-EMaa%UY& zvx){Vn(7Wg0B&<&+iHy=!4{gbD*|Kcz1_MWFxTa+%;Zg<*RRJ)?x z|JYf0v;UhX19=+S6p7S&>5(SYOQf?aoGaYe#FdUchuY0L z>41XRy=S3&5BGoUoC2)+YzTlCc0yLXW+I0S;)To7iGcIIaK7};vbW5ReU%;TCk3nS z*7eO?9pzJz;NSgPe4qegl zxMxB`oOw{AAfSYz9WUZozIM{qg_u`^{^9=@TFS?)M*e)=N-D_qQ8W^zj~h%a^u0KtCo!5I{t% zAiA)gMVx2Ef<>H{I{p;tAzSCytM!Mi(J36p?p1d5(9f~BU5~K4^yc2_CpD$X;!5rRS;qq6n6un5i}&n2dzLy^2!eHC zHTEvQU3BO9u4jl+9d|^j?xS5=s5g4(!tK}=<8Pv?`O@%wT!XfW6nH7e5kqn$Xl{>vRoa|Rf&J;xHR!Lu++>A0{y zD_l`}Ykkc>cCH3z{@;Jx=L2VG>NYpr2V+F(9JUMtiP%{;on-I$*oV5R*x8!8!m{_> zn(Ak3I$8?R=7Eu<)IrCO4pgM^N!Ge0%pu&Cr;fR71k0W zp-J}P&-{Ax&ugnYu5t*tu33R9JBUqssbRX>vuHgcw7n*QdV;-FQ{3zNSQhKqdS5zU zR*rw2lx#|5>)-9y{Zl_9B+qdbZA67j)8= zkJTST&CE8=-`;9KE4<5{%h?s|OZFwR6%Ik6 zt3%07I9Rb)f(`CUeTR1f!M1Rw0q-_)>V&X$Oeieuy>%<6w;NRydFh?!s&=PYWB0tq zOggZ(iOrFa~iG%koqIv~vGH_0K+47EXL~e!hKwL2UI8y~tzc3A_?;N!gE^J0(4pD!g-fmN)NzYHi0`7ed!=EC>LisNQD1xN4?O z3i?-AFRB7X0jQ4&fp6kMX5Vayx`R!-D{2MG-hZxgO&Sf%>Sr%brL!)n#xik;k6TsD z<($bpN4O7CObd2iSc3m4UIYl63dsiQpe|aNO@LHr$p}>6u^z&~2LP^|R}a#34~CFF z3@tpv!3ps$1cku8G$GdKIGSWg;{rD|3)Q?LXwqt(Oj464>+?S~LF%2&r|qp?=5=Ju z0wBT+K*%DhZYt0Q7Q3h?tbOfTKhhR8Hq>f!34(S0RjTzikwM4mH5^(s{-c`_oe6du z=$Cf(o`}@S>8MLO^%+%#1bgqw@`+Pboyen4Zo1M2TxywAK=Ld~HF0>a+_AQ{ySUIU z*mSjktw+^nblYQdyZP+~XzSEr+bck7R$gkfYqE;rbCZs{(EareC0KLj&X+~m{NZd` zco(9wmSBfksg)LbDN^a_q%N7>l_PBTM)*|1=ic>I>hqK$J*uE;6VXj}c4oBHA9bHh zZW4?CKYQ={Yg?98hmASsT6>>!?|b#Cx~rRR8Vm#yY!kq8B1M)Ge@hf83YL>tQ6xvQ z@ed`69Yy(Hq9pPM6Jwi5HnxPK$To^&MGz|lT#|IY&Os zwe~spRW(sUc=dt1>Z<$P`|gi(=GlAx9AnIVQiuT~nnn=fx|#oBIl<$3ZRfEfeBI~I z{pCO3ww^_{x=DD^hRIs6>`6n-E5 zKKi})Q}{Xh7M?T0HnF1@_^4clj3IM$#KYV~4@$f4T3uPJlID5IAIlePIt(2t6ig24Ld5O@MK4H3lZ|Cjb z`_unnzS7hE+56zn5BN&!@GjxAWr9~LV_e&W`}=bJJTLY5bsuFiX!k-eu0D1sHRXd> z-BsOuRf9gXJaJu=zhY19?VhP!F>``H^Or8OgU9oF&SM~a-RGTmo=5A^d-Tq2i|(UM znsIG5a2_@xfxTyS^&s87&x$Z(VME43KSw{)PtnH*{Y*bIHu^UEqKNfGCByKnu}qPgj8ZO)O{ z_-&WCd*uhO8!Km{J*X62N_b_%oSPHlw z?wc`QtuH_9v!jN zcNS9tp$~hE0AA?{KYS**z7+Si!7JhL10Qn$f7RId@C@t&#=-T)f3eJNma8A+g9l@f z9{zA*`gmT?d2Efo?$geV;Q;;lb8ilSK{1Wi#SHFR%B-r~9l$fh)OyS2|#OFyI^u<$&!0^K5U_%5^35 z;EWfTO-_9{le+4WUQrA#EX!+iU4QeXD#G3hbN8PA8hwnV= z2H?fZ`-l;Y=pN@5P6(`6m1quF!4)cX%B#%}eGs4U>L7Dos3Sz@i{BgJxO7}zX%Kwi zWs44jj5m6ih}R9_%fTCE|L!TvC=eLHq%_3{AC|D%(?NCVv_N zW(-IizXa!)BhMuqj{l#oKN;nC1c#1&K}NNd-=z<}NA~S`*L~XEDeaS-3vCjYF;v!X3J@9(Mq96(DXx7T9QOya*SJGH zXCz4P4@UI?a$Sh}d z#>*K9_mDU+lp+@bWOCt2$Tgo(rioM%R3qHK?b2P{B?PW)c>Ve1^2lmQuY_2a|*Sl9<`RXc&wXHyZ_yf$;U8$3XbHPv83eyYCvT^~g{o z!dl^-Y(1Q!qE%w+YDR{X0+E^OUShzEf`S4i~;4ifNMgA22HwpY9dy! z-_j!-VgyBrD|d!Vjz3BEyNJewd(5upRU`_~*?ZqM0N(oP`Ev`6i15Tlit1Pr+)rB} z%W?5@6En@#dBs$(LY+Vas{3PJ0t2oiA_*A+F>}%4zBF-Q2}zL3Yi-F{gI*jU_v&!6 z0(Y|a1yY!b(A;g3Cf%E301!e+>cBhie1%e?_50_~O)7iueY}v~yqE^G-JP|R)4c!YP};siN=zL@N)%9^;kj@#6e5aLQ!C3{y-T z^4`0?>X(kbL(=E~w5`$o{@wS>dc)S-b89@jhl&Kn&l@21s3M>TREgAE|BzH*thsnl zD_>nIuYhiM4AHO#p%bhluf)MuKV*v4?q{eA&3huvH?xGErHrJg@US z2Ex~UeB18d`RZFAd)j*d;|5ltQ~?|+IG_9dIRXe#Ra>ka7Q0!q^kIZIM==3W3_>cd z10fZZa9rp9z(eO2U?8YFn}38r(J?REKTUMq=-w#inx+vFBzTE}n9h!uS}+?yVd*hvpZpgue(Rl&ee7v#B%lH(t04oXfoLtl+c`1|(4zHbS#H)`ssNJR zhbuIU`Y~hS^fD^DyW25`(;OFW$g81FcVUqS_M7VU~#O>^UlnIpp03ZNKL_t*90Z`L= ztaYun78#XzuoGrtqG}I{p=(m$1@b7n9d;zijwiXa(XTEY?yvl!#eRjY+&OVqW|8?T zacyXs*C|98LP2=6_80!k@BhLVem#0Sz5n84AJ^8M)Vv5wVJYeXv?ik1&^p5bh^VB- zd_7bZ$+v(`G0m-vsx$J<`gmVJFPF6vJ6gfQW43PiF@DL>+wa8XFrdD@O7W)&4k{zyv3G^)ZCWY=o|W@E~0>POW8mBwmUp~J>coCv+L;z~WT4wo%P*oy&BLku&#T(KwarG9=DbV=u;<;Y^V7j);#-_l`9(HiU zD^X)SkkMhxdF~zsDWvX@kqCMZcL(6TDz%?gK(Z7ZOhiG_1f_^7&*w%T<*P?TbFbU+ z$zn?h;_m%3h~-e8ym?cqUbPBkpAHUd40Bvfu7>mHRj7N_AeWf813UI`7!S;b4?GqU zlA5}&n1YJk6#oA6=k0uk_ab3FOi>F~6R40ZHbUBVZV`wO5s8jy-tU?`sb#IUl>7Hi z(L+^ko*nCQP|Xgcj1u{3hwxZ=cEQs=5J~4X|;e;|6)x<$Gopn%@?fdp=mJk+L8i@sI zknZlzT_lwTL20A}Vd{N|py|Gs9fJkB}J?0ah$o9nkr%O)@HrBF@RSAEwIr_2e|43&6#99rjI z28&q0d;CC4cInClFD?cYqpes2(hsd_4&b2B` zss#85C3|EQVDE1=9dy&o_nAujS>m+diAN{CRYQ|c;+(}INsYYNeq^0asT&AdZ!Pq; zbULX?9^Q`|8hYWXjPCC9P8~`ihpXG4CP4scsjhwT=A4uFKPP?D^Z#-6Huvvn!!hW< zZMyzWr84~Pkb$r-?Vmj;Q7cekI#*W@eg;=hzh0OXttM~71BNy3Wyyx8GPe1KzVn~S zUKdTMt^PaBTH8LSXd-4pm!^ePr_5 zbn!SH>G+OJ+LQnwo2Pg!@|IMI#o{XkX(kI9;Zl9+j%L)iX3u9x2NoDjI%u4JsqJ=h zh_tAGdBBxN#maG_-%xRhlaYA?FXkQ_OqwMis5<_^Z5E zjej#lY&`TAM6yxkpycSgITK{e*30cS?+qJA{vdek;cr)bhwp(j6)VK1B zqnFuf*Sj=@Gr%}w!%W?C`t7qfCQa16x*sPDSGq^I>^A<(uY6%uvZBbXYWVod7X^_R0yDl-%b@ z%QKv!p`O?Gh(u<#NJ#n)$ z`rrjDd6+?o@kp}-1NIv9RM2?kVRj9Zdea=cn1#XK%8YqiM*niku*K*6 z;bG&x`DNYFgB3F%!PuHcQwSLcO8a2UFSN&6s7`2aQOdw)riVypD=oW|L+b8o){-~p z-QJ~oZo-gTtx3AWX8gJxwsy3hIiqhqq4OITJ7Y55&jUk&5vej^T2_UMbXY7ZcY1P- zw|=(|kCzdb$IVx_%i^o96DT|Ya*)&mw7FSh18#j}5T@y=THJ0Ksu-7&{H`kCs;{iC@!#Ru(@lDp!v%0`5PNIFj$ zWBZf+05m;rwp3Az?}O;O!uA;sZ!EXS|tth zHUyU`Z^*V-Ah$FC4zS+k?QA>r2x%E#~K|B2Xs^qnOC3_43#g8n>F5f{L z6BfhE((X+_G4{29d6-eATzby3f!6-@cTxyt4n`gzv^AaY6yYD;T#q-XgUxDE~O4- zg@wnLFu3(MGDkHNbAhW8$`RzeU-k(BzFf?3r1AcuIFadj86a*M22X2*v|PO~^O3k% zp(yRdYgKL43$;+j2ga%t?~_18s+Wu_Towv`N!~a?lInppU)~jZJBf2@l_Gp14?l;< z&@Gv8YEivUiRy3{h#P8vje671VNHk1fb1|+&}`(-&&Iu zvcwfFVaUjfm}_h%92z!sc+@~e~g4!0hZ;Xj^cRJB>YOUtQOP%t(h z98e&2{MRdd#O>VB7pU{sMc2vS+Gf^LGoE1=oe+#0lp59_fxSCXqcp*DkpU~-*7a@Z6&YQgI$9N0W^ zy*}fz->*r?^JJt$(zy1db-9V-i=7BT>RKwew3^W(9xGQ2p`E!W>nF~dNUVFv6Az1} zg6<~}s-N?nkUH;9&m6cEU?Y6jnX|^4rKEEzTCd6C^EkAYVxtfQ$}1J3GgxYW4H|KLC4Q zesN8VMR*w5^q*~Sve`(n@^GZ1vJOCiGDTLP4jokH&64k79=cu;!qZXU}vx{(7=#F<%( zC<46Mc_T+l1>Q#5S3z$)H{&^+({25{uZ2#H61cFuGh4c~5Tzd(ic(^HCt}wAzeaVO zu1k#tS=r~w1A$6GNE>vPpoEpuVlUJ&b>e)Ky~^dtPT5H14MJp~27zbcmOw8M4ebOZ z-*WqvF&vqgIDSPIA>$MveUdbei{ujkP?p=Lrqf{;rI%(Pq3xeB30g^@X3l5X5g4T9 zw{n9|rzerO^)`i?MY7Wo(g9ODvw+T_%=Ew)4G=1}bqPZ{%k59CEiP7bTiv%}QRF#j z((qsWC$2LmmB-qK&PNnH^sPlg^J$qINHG;Rcg$t7t_1LR%Hw^Bo9)CaP5p=l=1ZX} z9XxjeiIl3=Gkg&7I?$GH*3AP6O@3qZKj9-r`0sI-o|ATE;vZz7h+EACdTnn37X}`7 zbdYq2M+(Rm9vO*_zJp&oU-M?8iKEgydqn!xwj7 z6Zo1&_A02SNl`n}b<8YmcLDdsO?e1|?GumLv2E-FXsz&2J<@xY1c)pwbBC{#l(obC zb-_XSDLj(dv#$Sp9*TQcmCpBs{0X#+)PQDnV_o|*d*9k^a9eRH#UOj>67T~o-INE` zT9q+_AcPoXQg`g1&E=v90RQ%|;3y*&Gbmn6&6r>I`Hf+nN|&8yb2e;50Kw!eMq0fj z!l1z3O0F-+ro!a`XERVXfHXK{-?Cc%d3iX)1(Ep^C7O6anY>jHtt%e749=KRVVNnZ?0Q&+E zaQTT#;qUeM#mL4>P2zejVe=MWkbmq@?zc_D}0KmJlc>k%VrL}Rk`pZpm8h_+5 zjG?LzAN{+QZ!ONqQ8b7DaQkgD!LcH=*%Jo}mf_o!YE)GMC72&XR|Kbl0`c89+BnGx zL{S)^a?oLgGdK%DyhIu|fOWrKPS@B*0OD~~$VH{H)ymHF<0KOsVc=1G?U4BvW>ab8rR~FfH9Q@TR3uicbpuP~U#>!rci8)Di)NkjvXN2$#Yu`gEA{i|IX6 zz=(LXtT5vW2C66(Wh)_~^zbMRq_2rpyz0Z>gEy&l13XT`yOKD_@aPq!_aP(ed=>yK zXIKLeRWi~y$oSJrTOq9>4mc9@1~`vRK}ama?GuH!f4;^I^aCk+>2J3NlceU0wqYXi zex|N3Wo^@if`1EH-Z5%cq~=*Lc9~lLH0QxI=Sd4IV-Y~4J#(0w|Y5 zTbSM+6q1ksxeoonucRE`w!4*saKaDS{V5lD8eYAKqQVV8sfr}q2!)=Ey(eJ_xg@E0 z;n%ty;#zwU$rHV&W$k}FE+A%~D)%PBfxl)DWiS-C#-#z!8RsE$)6YXeRKdUd4}55< zSt;`n^p7;r__$0#1SxL@mX$*Q5dobi3Bs6!+zOvTGKyq@Uyl-U{5$pqF`InG@G(J2 zGoB8e(VO`vwvk{~>{r-maasd$x1J0YXZe}G&lk!P1mm%ge|zQO6@5noDsk-qNIJZ0xRmPkJC ztUEpXm19ou^^(|fO@f6m5!{_t#WE%77(`adL_uELMERy%kUc6_xq$GxQDM#3Um^y^ z=<*64{fN;^v}JPT4hxOfZGcXY8h-UM9o+UH@Jp;6X2eQUAZ5m?1D^d@r3GDKX$?;Z<1{z%7Wm^o#QGh#jxhU3K-0_4&X`Z(3Rr(t>QJ1_EDtzglm!V z9X;U@Y{<=94ZT0hPWTR9qZd0THeBQW6IE^!Rfj(ThjZ{B3H>_&iZ;70Xp|zOODTpN z?+-1bUBtkL$I~Yf|7&HC838rPzBmL*+!h)R>h`6)T=HjL3y;r&yQg8J2|?T}4HX!W zx`E8s<&m{gxCr?0Z$}b+iGvIRNzeMo6;M$=5g_^KME+d@kr)SEI8~v<0=G#~MS5{?%MF%s+axYQvds8owI5D=PfN(5u^xSSw z=c~tp_=!oTS8RPdyiJ?q3CXFA+bjuwoXvZ^)q&lcc)0KrFr99SqEN?^r zKMAJSM#F$!w6z_8kR6Rz&;h>l^VZQz+w)o9rN^V?+@g)IH|7h_u5O4omt(LAQn5Ru zlN-_krlP+xvt`X7?wZm^`8T1mz>h|y;iI;KGTG*Roqf@z^wXA_F33phaiu}?7jU{9 z6H+--7MB$m0r*PdYa0n-f}WECOs1uSL9U<$iP%pl(Y*Mv)Sx$ImsH`U?LN7J%GwqI zFID?={C;D&mp^45k0lm>kWwE8BIAd3fYRL}q|DWO8N|HoxhO4aRqgp^@0f|!DT46* z#6|Yw;N`9l^!nIR)YuwPs`4J*3v6Ali_;Y3^0(ghj(^H9n3%9d75h6>kz`(E zNh?z@*EJ@HGU_(BV>J!4#@D`}CO78>HsSL0z3B>XNI#MaQwsTv?p+d=nAl)t?WZK6 z`RgFn$KUv!I|wy1W-m6gjGDNHbrLYUqe<#-(F>}HwY@z zmDsD#W<@Il-oqtDn|~wLnQwUXav}-Z%@_Sfci$;ya;L3D31E&t4hE@z z{D~?3roD1-mN-}nJ3vtfBgm9TD{4@ifgY?9W&LAynjN?po5&b-0ho=k_pVf zC2zg8CFu0;F$-pqw;e1pXW@%75f65g=4zG;4NHHGZ~vay*Z!@~ONqj{oSA}=!QxV= zp_=78;7ux#Vy*G9gbRTw$h7!AZu3){%(QyH3gCd=~}rdJlg&x zlWyj)b43xxSJ|wM6wG_#vvdm}95mEYjYn=I;rtCE(NYF}OwSMC1nUje3TC6+Wk{Yi zpgcZKdU2qcbCbMMMKJWbVEkD_`$PRLY8HSOM9EQLnkiVK$mP8=CJwFkohR>=%-{c03MmKUV+`D$;<79ERq?wgV0IyKTP6c0xYqtI8O(^Sq<8Wb6T zQbIeW&!+qX$Bz75nSWS^v{_MT9!qnUU4~!0QZ;?!!?WO1#gDeu!zZ*pTAPChC?Y;bFS3^Qw=@^z^LI-?{k-kl zme1JHs0J1o@h6eh&4WAJhY#Pz6ZeB!)!qsW2N{Y1Yal_={?yt&)X#+x#%+_?n~Tj$ zGK2=UTQ}sEP825FZhBLhq>1NJ&NXlcq|X>^Fni8)#SJM{kY^7TJoK0643%YC@elt*X|lfk_4TGUDxm4iyJO5o`+`2D#;DWk6Py1# ze<84VgTM~86cCvl<1xW+peY+^JszB3s|N3|lfmjRwTC1`TIuy*cL`G%lWkU?2xWoa zIR1XSVnBq--VL}DK1kmj;F3Kx!v^=v5on~=kd2OXzb3TQj|&T82}=`i5-xo0w}<(B zGMVvn-o;?WMh|Cn#1;RuYrlUI{#t%IJ4+eAjl~IsAOkqR!o+9&;e!T<$Rqg;GQ04i ztOh1j8(VzO4?Wcb4j7FyM}2qoSDILBgqXsZB(*cJzNVg8C4PEN8B^U$ziRoFZU?wQ zaYx34?dDa^z1mZ+G38=+c6=I8f zuEd_xM<6~CeD6@e$zc@(IZ&_TH7W!9Z4ivTM~;tCG|IYP|9SZJ{doFADtNkX4hDK& zWN;L&S7%muiu3ndNUkcM}}>h8=-2vRo5p%qs{j?adgek6!B) zlF6sW|GeasawSQ@5^I^sAwxZYTspg$Fz7-F_-v4S8_6h`302o0cLm2Xq(d17yO; zR%06W;#5+)^4et_X~k8_Nvf8vzg6WsdfglUSwRBc3{tplU|Rh{`uRs|F1&+&2AMh}doyZ{Sm`x+Nmv`U#Ez>co86zC~UASI^sq1q?H{Fy9;1VYuD}b&(NHUv~Mk zB*RYVIt(!m8t;R}y}w0UAcrG@;?@l1lXib6HV%zeODSY2rSrh1l`g1$k#z91xCGpu z9GXif=UZD}!xA1+p4Zy{2IoA#5vE$0`7~W|{xg}xxzt5vfDY=x(*uPB(^l-ygTLo0#xXmg?vMzzd}WaMq*Ph^Oqt`=ZV6WuG@CKatFNa~;$ zWgBE{NKnb@HtrR$Ja~Pbkde!RtF;AzDI*tXE?<%Omkb~YzkK<@Uea2^pYLcMmTCNI zsZUS89(sD0X7m|uFV!UL#;&lq#+8Oah;*TZ=$1SOh5UjEkt$`~I}$a1w|TC4@xe1v z3UvyA8b%;GtUkJnx!qPx4@aFGUlZzS zk#ZC>s7|<>_}zs*cRIkw9s(SnE`Ip!k8G|Fm8_JG;d!raYHdyBd+2lHojan_j#lg$ z_JA-r89~l}P^Ef+XF>Z)qivlalsbvHI=Os~;c-!Nc4*B~xdJKmfs*)3Ndf|f73KQm zudho0YuO9P;A=HXrxuNu-D#|%G!#?Uq=#HuwE(^=C=JfU z*Hp5aO2G%f!0=jA6ZggbTvQ$psLg! zlwHR|j6S(~B%>4Lp&-wox8cV%WpXyuF2Y?sl)`orm*tCI>a;aej?dAK&*9IHu0JMU zi&G=rM6KTa_&PPVe!G0XWFy(0eEh}aL+eqm8~^-Yq}d z)WI`Fbr^UfYLC1WA}cn8500`*MyZGM<%8}QT*H%Mr!j_q2-l7Xp$P{o6LPKR4UXjR zui8sP4Hq=`I`fZ4X&3uZQ^E70D8vFKcG$&Lnqt}2e3{+|~he{Pm`cSi;tp3kf{{(9NM>EN>zc)5U;q&p!HqJGd&jzI_2N*pPm zsG0CS`Q&RGfZfPUvbm#;>qT6D!ctQ(SoDWJb3Io@$ijZbXDqWLQ8RnW{Ac-4ZNuu* zk>&GJ)EosqvEaCO z(YN}nU>!9+e<4TlrM9TF^Wy|N>ldtUpXB|GqM{H#D&$AqLTY5lA7 z>P%6l&#?JuO0SDw!asD_pPl?`AX#p*t)p{ES$Z^eE*7MattBCLO2rsH2M-#|p&Z-g zN^mFla2{JPIJpu^bxF&ZM;4m*Nv+}MF)HREnNRLAZEYMXB0$b-x$Pltl>Hb|V^@Zf z%c+-gt()_3_q}*LH&5UHDQWjWNtpX%bMx~@(ug?M?#QZrOv3!&~t^+DYZ81b=etGoy=s*%h9k-+k8$}O!(_eh4*U6nC-lUsGnC>pZjLN+^s&%j@h}t!|?HVJTUpX z@eyjv?&+6<*3{(BVk}SY22c0@liABamfp{%6ULLG1FIoJnBruMV%2F7x4I{u6m-ms ztoV`(eupH{LcH*>T~R2IAYPE8#Fj~tthpK*W{4Dnn#*6MILmm3eMz~323%OSWxQ3A zAuhOR;W(50bT{TP?&CF84JJy>r@I2A7`02~f1VibRV*J0vtPB&nKML3&HP!c`0%u@lx^fsnp?F7=1t<@&V2GhdFVm&67}q=Mc<{T#Dkb#5Y5Pa!nXrW-;)x* z1Ku%*72lNxUi^riUnet-pfpw0YRv;EV*{z_xSF?3eV#gM4JI@ckWYbFw;q|XtK_2q zst_l_+~+fj4BVxOBlohzWrBRqw#W+=rRD+|KXItYul!*J1&?LNgv!dSQ5&H4dVfcu z!fU1;%6myF>uZpB+LXMRf2Vd{@%)GB*G-bgs>I9>@!KA5rqCJ>YDAA^{~LZTFTeSJ z>c0!Iy9|is6-^dV7_l(I)ed4JsIcXLqa#@Ie=gwW75am~Ny0qh>aQl$%b{*|N~3rQ zgEU5R+I1)U=X6ta?*+)-VjZHl@t-d5|Duvd4-FLa{fYfayz;-7P5T37`y-r1CWo}z zre3W5GIBS&3FxW&CY(3z2X2||dOEr~_(LXwt7;IKHuR;4#RwnD&S>8`X~oP|H!5KW z<8!JIf+(A`p)rsKB0OVuEPB5(`IZCo6YL`IHB(hnp%^KA!me_1cl%R59;a;(#M({i z*ov{VxLDI;wBys&+vf|%_lxT|?PuTNqHJFv!j4CH1Xrfq+HrP!;*~-_EUy2UjeM6; z`uXBvaREy0Ow}4*;2FHK?>z>~)0&=Ed+DgA5lv>GTklb0>u9^Wq+r8X5_STO^Fo5e zML){m!z^e@M$jhM&zlLZR=gLz-AEhB9UYFM1o6P$mpd6Ris{$C9N&}OZ$C0eH}C(x z$VNZDT^os8*9O4~+xvxYL249`KM%~Kl@-F|RPtnfY3}QVXAj4-)OwW0C z^}GbgwypS!<=EVQg3?~TCJXGjkSVbsXRbuxq#b5O#A6syxUtQ#+>#MjNLJQlLo0?t z2!=#mmZ7qL54!ZU(38_%@jMKva=iPk>3cr=>jBR4>u*x+zle-_zvD-acSBYm1kPWt z7p(FZih~$tX6T8QPEu7w;|ys1(^E0%}V5P(c%5yQQR*XukId9M`_GCjJE^U^~w?BaK=k?4}& z7|qk@*te&Y_uReh&rH8gnZ6y=IxexF{@SakO|?v@O)phK)BJq(+qIl>OGgegkTygr zy0-#HKxA+G2W)xtb^J27^46@<^Dn11{0jW*BXKP3<9M*B*HHjQRl8tg3)hvb&DMLv zniSxOm$5v*oR@J?Q^|ohp^sX=JH808Xv1kdBQSMpGhs6!=G#W?^KNM4ljGggMZL!d z332wfC#|>D0jlyr;mV_)yo0*DSUf4AVdJ>&2(>!nAvC!8Azv^{$ie|6+yq{?HnTYe zej9Tld>t8t@|ik(=U7@r1}0qv+9&W}TJ;VJWu>3;w6)uCp$MLiJV`35BSYxG5 zlDvXK4nH_P$^mHRSZT_l7VTBW5_=ptYkNhPDcP3{x0-nQI!6+iww*4Ua_+bB`Fm@Y zzAsFGdM z-op!J;A!m8M2oOR3&0w&H21)$^u@!8(cCy?Z?);mc_Aj;Kfl4a81Y;edse+v-vjgP8Tz zlX)s>VoNlL!oWnuMM@+v!S6G0QYOhLV&XcUso%3*fq8q7e42PX?T9ICf?}jQQ*J{y z42(;DV!C|Wr7Xk7AA-P*{fgHy+l|!8o9CkKk4E3tN!#zFb;Yu0onET?ieG+RWt=Md zoF9GhIxs^oY zQMZ(!@T6FMDkRFn@88lWJS9$;fvtDW3E=av%r(8E3l(3^A^-<^0?JmsDTZt|l>r4e@99K+9FCgL*%TH=w<`r?-+914 zsf%ze(Z~@^abkqh6dEjC35%3%2Ka)SB>fl1tA9t@ud2u!bG{wN_$`w9ZO`VcuuBJB zE*YqS8dviT!PL^`+(Olm(yl~Zg%}oHhXJlM)lH)kmhbDmBp5R&lSg!lPPs+ia;MHW zLLl}s-q<2&KrD88t`guQdW9m-Bv!WIJ1io2Pm??cLjk|0?l4YwLM11xn>7@g+}wJ7 z&SVz)_TgyO{jqQJ{>iFE7^G9)|44$HzR}B~7E#smzdM(eqN72YAOjgnod~pUY%u9Dg?!vQrRjii?I<;n zPGA>%y+0K|m-TE*ucBWkMR3KtM#ASG)6==+^Yc)HSoU+ne^*H2uBVvnwQ{}t#O;Sh zR<*6x-ccG-Cl;1$a@C}DeWFVP7b~^QG411g*PNQ=c@)ACWHWy?nA6XvVKQ9--uS4o zJUL=2G9bq3*Z`UhH!Kf>_tS{HxdH9qiH6P_?^|vf9b{9+l}#eYAFL=5I(XNfca^74 zCu7e?q`$IRRN8bW1!uio$A5@>@GBR3&v5Qi1IvlYcV@wdtW-`(6Gzy)Gcv*dIGYk_ z4Zf#ZYq~4lSiYP0wJk5SG+`~IwMD`8jWrgLjxX66Dey_<5rgM}&@3kME~Z;bQfqD{ z)B_4#70-?ZQ_R5>hu&hX=QEP`Ozn5qM`uNE+orskx&-m;IXs^^@i3Ft>^8QX<5G-p zn+v6I;HCz0{Y}L&@^rbP?njBVLA$?CoNKoR@nSzohnkDFklP0UVg#JHBW+KVxP{XUC0Tbz@;qHELZK-XL*AY@`;Pa6j(*#R zX&e8Z0wwQpB%g&nBcW4?vqhCS z?uq4PhflT{b=K@TPcsP?RUQg{ous+jc)l)LZBz9UdtUvoSj9ZnR8igbO$bC>5s^8z zLJccq>cGyqB{ zRHa33b++72+WI2?olpz1!I9&dDoCR)cOw03JZMxc*YpT9_|rB9%)4wfNo~q8TiTj@ zFZLZD6`zNm&qY(gp02;XX|m1eWJ|D&of?8EiSP|xQEN$a010xyW)_m*(B@)RkQh6- z>!sH|8En9GZ5q>P;8M~P8#APA7j0q`fi^q!QlubZK`*KG>3NY1t-T4v_R`4c>&xGN zFVAQAR16Rgv5wb9F{0?QV281XlxPmt95gRvjIBHrJKq2NaG!+#7W499;`A~3!{bH@ zfLg`tFzVvL>ef_9lagcN#Q^tKxTO<1fsHo zqeq!yRe^xrAP}fqM@!wV^P_A0+c7_n=nQy9a71SibiO&~#Uu2CZK)PYgFVahB?dHk zRt3hE@X?zoqMEIt&UySZ_NejY?m_aocQJ#6L##F33Z#aW>S`e{;9H(9!%|x29avij(dR8LP|J&HiDR^Rwt>6S!tzd0m$3$(9y76iXS<5nb_s z4^#E>Z8u_UMW3pg{m`ZLem>`4)U%>4)wAQx%B5<}W;0PMBX~tsx44ZCAS)B(sPC;a zrG+NVl%7XW#A`Epl=ArFW+?h*_{g@dR+R1SD^gIAtPYqZ9toL{`c>|Pt&vGm()~(A zj=AcA1Hg?@Uc zBP3f_BUSj*JXz|s0grk<#>N~VsWIa+&ZnAOG2^_$o9wDJ|3)Sz&3G>!LBi2QYV&SID1GAcn zN`#Ml7cElsQpQ|i_f`7mlO471|Kx44!rUziFTzP+(4mE!14=PaX7KB{RfMSwJ=HMe z1JuSZ3gBgFHcIB;o!4lg!n?;*cMbkes;rp(pt*@z4ZGx?NCtUKhi0TQ{ z?I;(O)kEKanPpUcM|1yhSM@Om&2JEXDb62O3hLCJ?2l6Xr#8igT-tg#DtcQJIIDN# ze?~E6|KqbyC7Pu^NKS871y6U%n1nzk8}WI?BHKNs4@`>;H&UY6=79EzmE}6DPg_@6<3h_NR2hPcP#98MQA(xbc-OEa zy&fh|Sx6JxAr?rVN<40E)D(*)CLS0-Kt`ZMP3nlfOl4A+teL9}&PO}oR_vYHp3sSZ5}FCmzy^fGq#gz9qmH0%KZukl0JJaQUOXWPBb)uHE2p^}e(26h#o zlT6Xr*>P08g>-`2NS=ahNpi46rk)+Ve#<}cTpzyo?q0 zw&`^m)BBgy3758i75F`MIutC&H#1j83%%7L3{H5wXb9_c@k4Y=E;Ngv zWZuz8f&~ICfE`KWXTWfe@Ph6 zaAV_v%F&BN0Tz~Bt@yKgVi;$}7f8R$$g<+z=)|8Q`@;qYYeBWV~e%3|x#7~RmdlvyhPGF|pLWF)L#;^&> zJ>GItH=n@m=h2or;h-Cp8&<&O{#hG!!F8`t_b%T9skG@TU_4b_db-f5>QA?FLI~<8 zRq8Mj2HH4V(>qgg+s|bAMep}+qraWe&^+#M@2%hOY82#v@EQ=smMW%gQuV2DbbRc! z7W2|nc1DX~aVHfFgh-{8zK%oCF6VNQ9XhJEVyyK7!w5pjRJl%Lp|Dkit7^D3o5&)p z*fh$vUGCJs^s}&;j-p+znw|&_9;5mJ@w|5+72Gsv_`%Osyc`eb4f)MG38%&7x4$%+ z#^a6W(1JcI3Y8To0z1}N;6LZN1SV|6@rA|DAlL^qSApy9)LbO;N!x$;A@bL#lI zKzeed4#rKl$#Z0&P$=dN&DRaVmUpqo11?*x6DCXE zB!&&4v1uZQ4D>u@Y=HWd7`fg^Y8CsOFeLc#p9-B@q)K25_18VYcCU4wYp1{U;az%w z@^~bzS8!MZQ+P)hd)c-4?->pODXr=3&?Vex+k$YR5ItgZgrRqTJ^pc+Q%)@+4B$S+ zKmk28l&U||0_jgHOCy&@$Ga`)F=JpevV_~XmRo!2#Pb*tItPF{>atJ(7;LDdRBEhV zt8u>w@i5;ceb@Y;@YRzw{qLG0%SUSRM99B4@3b@1U{GxzJY4B!asZN66}RDf?wO}^ z;^4T#KtgHhH3}owaA3m}HvW+zI9p(eNu&(Db1<2W(@L{i`Ngl-cWOY1n#iDbz!Jkc zCFT<`&g_4in88kf{3^tE_N|joyn~29IfN?Zd#K~xd`wRBSE$%U(OBEX1+RNjND+}X zzZC|m8>2D@ODg;}tTIa_7+`tq#5vX|tP!j@Ky`&c?7UVHRhO4{y}*Yl%Gu}l7J>!J z&_}QxAL9?0tr?evIHm0Kkyxt((#mLeVEiMs9htS+n9|4BbGR4AI6TZaoH&tD)RH{5 z?AJcsNw=%#2Lo*sX)l(K|7L$W@rWtja#}a*@aeT)6xUC_r=SpAj!i4;1nrSy-=;5& zvrIb-p{3zzaK?|JN?Mo!Wm#0S#gi`nZ1~!|x_vwP;u#hZU^@T8pxp79z6J{_o=*Z% zNXWX2Cwr+f(w(|zbCk&d9TEr6qhv*z$9W^2;DubkbfL;&uss@(4^0L9MplLjIzR+M zCk$k?!esgAP%~Oxp12T}oaT+G%$`{*42P7E&#d`r%U7}ej2XSndD;2Bqn={WbM*XD{(|Uy$Z%4l% z7oP8xNuAfroKIqOp#NEUbKwu=%e{7O89h}%yh0JjBlU^UG=t)5X(kw9sIyoJonBzn z@}Ca4#FNSG##Eu16J`GUeN4>voMV4|zvO-M?u>8B&)-Ii=WB)r@@6og6Ca!nof}mY z!mGH}cuY0eU73*XnhK3`ZVopT(z4$tc-h6l1azA7QOCw6BP_eEoY0XbNd;Lgl*^EQu%lZLz{MZgm8`O`Y&FGcTwM( zoK;bu*2%Y{@P;*1_3h}znZAU9-`2()P4Gdqo?>lmOnE66fNgI2fbsYzouNiTFaVFN z!j8ecz?`?*7<7!VyX@aguD~4_XZLg(rD|}zv5X#0AV8K8{UD)oQJ6`&S#{ikG#q#< zHT;zt6($9Eln{-HHmzEqc?V@~`nDx2>FJhcbfUh!ozf6Zy^*-_o4MjTkeimwr}R5S z#0~d|HoRDYcM%5>%{pJnfRBFlNx3jOUA^dw45|J;-FGlPc$C4b308cyMh@eZ(dBxn zW>96wN_`rVo=(&zC)UPVY=j|)rKj_o2g{63;JbkZl0-??S3UBeFR@7D}Ls&97 z8w|7O=U#)nRKH?}%oidPQ52EczQ11*t6^!ST$HImRu~U?u1Jls5Ja2W3+$2 z=EQYIH=axS^U&LO^@%C_*OlH2E8?B<%j-@gUekBSVt4FU9X~u!3S~!Jo><2nm;4Nu zou9Cvn3L_NxCYYB995tS9=U--@Tf&RE-r9t_+Bjj$2ENxZ&}aK5e%Oq*YB^IZ)A^#zGExM8Z&~mycm`zn~89 z^ub2Qu1ko+w#oi%JWv>C%>EmUZ$M1CsG248cQz+ zSTXCE_R9mldxzPu^gRDT@|@8Z#gUdWW9y-(Rv9)ez0Q-8+C3pef{fhhg^Ns!S#N%U z2dhQIITz#(;<>chk0xO=d%0OE6`OJ^>uE6l8q5@eCcr}1c$i`ol&#~Z7}dc#NUng$ zHNfIp6-=>FNW)55zVm3D4jA{6{H}?PKd4nDL-zDHt-_;*4TABDOi&x>G=6ESH(gV6 zP_U!KSjeEZLls7j02{uQO0Znonh0-tKLP6O2St&m28^TCh36Nq&$8U9O;mo{iiej?b@(VZETp&ylX0j3Juc6IA!eC? zUzr4D2j+-OIh${XF<$BwgLEt5ZSa3y03ZsTj8hOmP7N6&5Qvf@ZrHw_-TpM>A);3i z-Uejk4oAlQw}N}1Fgq)ALN_2U%K|S2*MrPo6qNd~iwgS(>ohvvTMWws2m?K=OO{bl zUW@10%XCnd85e+HM4l^DhE6U0*a3vol5c77BUADdq7de}_5r`@w#u34J#7O0v(?pb@U{7@7#;Y6 zzQ|$ZZsScXF)-yfH6x(%JFH;cab*(~QE{Z|; zW`EttWY=WyuBKn)Ry@dK*eU^0C=3aJMi^c|r~r$MYFz}HwtI_;yP8o#B7NmN*G1&# z=OPMZV=C1jn)0-y{REz4;Fl#vTXktHWGwzSFX!l5)!630OFIiv%|1w>#xOsqVrK46 zA1Hk@=>Iw#0Ao#65d|`NIyJ$m>ORJ&Ry!WPzM!JwMF*N^L|Ry5zM1U!jfRw_p{7fS zN{e!eg*6x-EA=Y9u!)pojP4DW6f5?Zo@jrn0B!E8(az3m31RWGC!*)og7!u*!d9pK zogT|ag0ICWr5Cn1nqlKp8{%k=EV>bf8h|tltx1L&aphmOeWXT|+`9G2q820?U;muMJk;$GH$9g$&2D3!RX9d2%`2kjE> z=vrK=FRFuD&1TGzMxs%m>;T+Y9H-1dcjigxifsT*FHJ6JEmm8bi?>}43rKpiqb!wX zM(fcFG*Bx;6qNeI6**i)zg7|uELU#iDu!ucT;M*&ixB}e^7--sS`pLv!Lqbx)Z`Pw zE|Duf2kQ$e-+Cixj=tT@pA%1X&tG~^{tG=io}SF0Y207?U4&pJlY@?UIiy=6v8ce~ z<#g>7)#&Zskr#Fb;@iId&{hijNNDzRfI)z}j5R&cGW%7$XQ+S0I!ZJSiE zB5k?c_fibt^lxpL;_d*q$o~TZLH)jjqV%R#7T)z-S@?p}+OgYz@{{GMBYSeq1s{Cy zE7$rn?8z>2U}cj<`$gF+d9oerMq;C(;Fz?j#e1$MaeG_5LlI*pMgTw&Q?+v7y{Am8 z0Uh(ENFH%y0G4}(Q_4JzmEd@mf-M#wWe-jqjjC?MteP9RVgM_wU}%&mdrk508E%y=NNl^ zhfGb>B<36%fGXsrG2~)e%D9=P}k}^#P7NV%J!*)0ZQW1!m5sVld zlP@_0ULE*@YrTK?#T7%rsT?`7dH(F=j$4nNK7A=RB1vO37g)`zDkqOEB}2=DD#5jX zO;{Z`bOZ=hH?+Y3bES`|IcRySV^TtNjD%nYNzFTSj6^t^NKTGsVh1FM$bFl@!To2`t5D;-v3o~Zs3IH%P z$>Zv?v+c0(R0bvn@0gwUJ>0jx(!&PVZvN>{-<(ciPu_jm^9Zj~nKZ?qA5)5Ew6a=& z8Y0wn@{U{}NvaBY@;l{WMPMRkro`w7a@SX$9F$ozyhl?@Q4xR{^FTZ2$vFx>A6-N; z1gt9Q^<7mZLTty^6A%+INm5Yrfta!92pNFgVCZi;y1G$Shi|<9?;ri;6<0+a`~9*S zZBGsySYt9U^o&gv*>NbC31U)aBqqe{{i>;Hb{xU#D5B;(WFlrn3xQJ9lrrrAB7k$~ z91^2<)GMe6h-idZM=eWgqA_D`(Dn{}AawkR0iqDtd(4w+ou|AjasWffFfYw$&f#>&F5dY5HDAaJ&tLe!%?F}rD7=#dNThj0FoZyA`7cYEQoIc47;A+pikf+k&b2H| z!RJW35`ZH#G-f15F=Iw%=mqi)iBQdA%3)+^=cJiAheco}@_|2%wuge(sq6va^()(TapxV!Hn%pmNAbwvm8Mqj31TupU$FB?h{%A5?9h2K z1Lv_<5)lZZnlVDQd2=#954J@@=a2{i%zJVUnK1WU*Nw3w1FOa<6s;db2-pssHD>e$ z^-52Kz!*X(2Yh7zP?-F##J!sdnw9X>cvMaQTynL$q7F(V*4 zN8X_eLBZDJuBv$W=vviOy_G}%^4RDq=>Y&nqvGD%hQD~~rTuHGy@I!;S5 z&+7nd$2&VJOJYaPVOdb&5gj5Sn&q69%k-OOc}wJ|CLlP*5Xigi30V@oFiPIz<~S0z zyk&qu431gU>L#uAoG}ba=bW))Ea>QgRpYw1a^q9Kxmq0pubpYW@b&M!cIuZWU)ngZ zzJh4QpafMUDhnnX~6EzBaz|_M_*|PuTSQ`BBje1eQc6QB$&}5migc%0S4Jsl|{ei7}&OvMXr) zMo=R}Gw_~OXSB!&I2y;g(O!?U)lZOz1A})|s|^R97)$T+RM=3`jR#k^q~3q%<{$j% zZFWk$CHdq-tB*bPJSEz{J}?7kdU3OMp3p3ciQ1$}sSyK2LZ2!vrwwdFOH9U1LJ*dLqKe_m^9Z3gCcoPxo^IS0-dQR zk}W?}wIVpp{X~$*VrPb1Xc`TkB$=w_pfMm4K~ftGJTvtiqX%}raJFy%0G<8xSN1OG zVNc$P?0JOm0Xe@(hxY5suUt5Mc-=eXA~>=-sxMuyWFK7c1OzA=JOMzA8UhhP*>^~J ztSG9OisiT{JMtcbL+=R?k-)pw8Dc``i5M_XsWA{y4m?;b$vH+_T?r8o$d2w?9S&V0 z`~J_~QG3AU%c;}x(w0AZOkO;>ap=IRsIIK`7%eG~=fYtTm>5m1=cfTNED8#qih`18 z?uLv}b6JpM%HB^e5K)VBr6)BTPhzjk)i0Pi$Q^?sgu)Gm!8z&|t}Iv$ioUz)*!oDS zqc?x}(SP{OyQ7MiPSwA2>;7oft7k3+_C+tO41$?8$s|cpuwxX!YLWs25c*ue;;2_} z(mYXtQZf-k1a>n$c!z+7h-Dx`*sh`)WNwt~FJ@kKC0H4RvUJYjAb2Gx%c4JYhxYaQ zgYp+oz^RjOGFjqE$t!2>7Hnw>1 z$o>QCs~F^ld%yVCfBX2mt%|MUcRzm9i>FSFwi-ejuJp=4O_a$*GBur8fvCk~O_b4g+}w_47Cb?297G^AQSA-F%4&}T6YBcFH3k&i z`;PBBw0}704}SQI>bd7Gi$(fM$(gfhG%9}gp+nETdcj2NMh_fVVY1OAO4Q&mDIg&+ zm6>x643Uz8fgxgDCqVNK%hGw@>A@f-t)ot=G_K;L5k@3vQ-(xnrsE{No?l(<5p(Hr zrSB49DENcN*1_p;-;F=|>04t^d*|}lGh1K&=C{wi_V|U3iKbN5*6$b0xUtzdL`D#` z;JIJAm7W7LVrr5mQ9`V$l#+T!MZrbj95~5zad`%BU8lN{7_|&UjFiKsYE00m_4;8r zD4fHd_s)|cl`G+%4;-kp-gnbSfARBobxZ8Y+m^l1=zC1=`=Gt}(z*S^73X<Y$Mco>w7)2ywJUK^(hzNj~M>fW&%#^Dob8OJW20e$4ocB4RiXi=x0Z@@w z_OGne_WY%k+&!J-Mf17<>xmy;{IXJIq#V+ZB434>IEjSDygb5Q$fg{ zx2rg*1k4Z-0DK<0fq;Z5X-Zm0rEZj0E|2kyObCPtU{HAWK8h3$R{K0kR+eF9t#^23 z;0yQY4>zu%9suCqf8~AO`K&PyXEKD*ID!EY zCNbxT7!@$rZ$V*k${f48lH zJ$Wax2ZZlQx$BnZ%<1j*VGn^09U5+JjyEn%>Tw$OoQO7Jk|eu3XxPML20&N_HnW`k zzp&YmW9JAF4MD`(8c{;_lq3}{02;FO3Ub9tU<1Sb2i7Ry_kMi69P)?mUqAKA3tJm$ zeOQ{&uoupr->fESeSJ`nj;mNFWz0Pw&?L)kAuD|^qJ<|_IJa55;Ib*8Y9c0Lj?uez zv}5qDC_)nPP8?&=E727wc;nIjMh*Y`i>p`{^Ood)`RdJo`QyhoE{xZQUc?8o^B2cQ z)_cnA$hO8!6k`AcXp+UGDQe-70Q!X!wX>T|D4CcMKt*HQItsm#6-)(^+S+O#2sJhR zK4{|5FZUl<9|T`j7xv%$sqg*O^+J{Ml~1of_RK36&yV--8*E)_(1ZZj)(4^*lhjer z%sFbJHp!YQ##$WXO5d5mxy`26_qmQp)$(9r6?2TiQIoXn6_f{EstgP2^+KK093MHn z*7G!2S^evO*qbKt-jh8be6PwM{rhkH^Y{K_w2}IO19^6=lFpnN9ogRl?;S(kq$VjC zFr%3PVTw{u1i)g{n3Rx0pt9#R3OM$`chvy~NFoh7TU+0^)+^XMBqC?u|LMDw4tz`U zk^A?ZeCfH#mJIuz!8MI|wv=q&YA+fjk)(MXVP;o>x|Z08sZAP5VveaOTv0HnIZr^O zNGT>1@{4`03E&;RN1$vE~LJLk4W zvFFe+viIycCIQo&_jQgYlb9N*qfVl#TJT&JKGWvqD%=F90Gh-ziWqz82l6EsZe_62 zBXkb8%YCmU96AO80X8_nj%WNla=;`SJh ztox0vs%f+lD0`u)qndip%%o;1T8u)72$1umWf{zj9o2O+shgs7`}gfz?Rghi1&2L^ zmG^(|(d+TvpO=q)^vLN`PhZ-MRVBv`4(mpo^8xkD#WAxF!Btg4v=;4>)wPHyGntz6 zi~!`R^e(2vOm$t8gR*qT4j*TTXU}ila`W+evVH4AU;U5&+kd&%Ykd=Wol{5fdR1 za_*YSZS?@q#8f9?M&IxEivG&L#nc?wx7r8$vwwOw`Xa8ZeCcY^J(0Q+CU6cp zpLImDOrEGnMC_aogF!JI^gWq?9b50ex^?LXKe-;`es5KN|MU0vs~4Vn@zq9bGOnsg zG_yfJc+V0oCN(esBqkq z?d{q*MWm)ls+c*(h|oD-lzs151#nDKYyo0>eqvO@}Y2i zZT+d2U#n}#gPk|GCd_Q6X2#AFGZT7d@0=s-l^zLD$pQ7=Tc4{>|B%%Y``{tQB&N(% z_+VlV>GXKhhPQwJ@Bj5$f6}WipZ?r^w)y1o;aXBL#u$^Dp&=tCQO|fj;`;j@`tv{g zyKDVPueyBp_ikTFr(&Yu3Bb%Udzy*aC~Da&#J?x|-gB=X4h>3x z-+mzUD|cOJKKRS6m>SVMS{^dBI*ZO1b$<>uTkMOrpPJH4U+n1^)Ps&Mo98*id3^@?iv1B0vP|L4I9yxI6 zh1CQ7pMU@Vy2fj`67rdE{_!&}TpDfGO_d~1qEl=2(Afi1&M-uT%)#x@Ir0VfhQ-mN zE5H2P|9Y+0aRub#U-<6%)1zv;Np+Hx2Tr!5CjbDfWlI5sY#AT|G7=L9@`dZImN(tJ z`Zs_2e_ZQzTmkvm?|pl8VbV+*X+)E?c7W!d!ERR|bh`q8kUCYko*%6De)5mM4X0yI z=4B5Ee@o;G-~M;cKfN*8tYRe+Ma4`^6_!6OjEGze!upZnWB>Hu zuhIH0SHAk)Km5_-8(WvEI1!1esndgY7o5#u-+~IdCpcwT&c0EGLm&qBy&C~= z>JS(*k_Q*K9Qs2?*IxM1_2?^~_{7&QzBa12qckGPRKO%(`q&yq^Lkjg^`}8WSg;q` zn88#JKm^!X2IXpT{O0{X{+sL3K|JxmAB-)*~Isx>;d6>Qa*IzOWPMGo$CW_7SO;97cRRU#P_y*%x(5^ z8y1^K#10O528XMMhEM(MdV#}FeC@kWJaKlsS;tB>S$2Iu!KV1vt`(P!eb{OL&!HuN zp)HsQt)pznNDf@Vy_In6hV^Iu@z1aRDlbd!|J{Fk?v+dRD5geR!>HX7%e!LN!0=RT z9t8pB<}T&wUDk$@4sCy^;Y*i^wrV1?F@m^dBbxM*dg1JVYG`* z76U1>*ok%1J*`tk&L+72{{9oc_^Wqgk$ZAQWe*77V{*p>U)el2j^mWtKq#2CSHCT~ zfb+)v&LcmEiOUz?oMW^MhwP9GDh7W4@wH$5@EW^B2kv-y>tYorNupWn`T!Vq__yfW z003lw+!X;9lwb>>*eL|9br8vjfjqjB2dm}p+;-?^e|0UZCqDJ%KRo%=`D&|4RZawg zDzpLNZdY_`Uy$A4aPjJg?&_Zbz}%KVKn7-@fT47Q{rwky_4ikMv2QF7ec~IJPH#2a zF*T~$A=YUY5NyF7!reClz>f2>^MK5P2bi@nJsqBW->)1RKK33=uK&+0dt;d1GxDh~ z{vpD#t#gxRoKmeSkk9$l0cx$*>DO}lXZEAHceW4OB;o9xGa%{s_p@bfDk@RNTh*Z( zKJ;%M{>ZN%|JA##2!IcK{10k8Ho92Fu}A|M1!0PUfMD}$$xm^v3IuVcjrq4tQ$lkZ z=-!i27CXnn#57r~p1cj&^9bJ? za{K*X-aNbAjHj{CnaMwQ*>y7abjc%{{(H{mol6^8d#JnDr^c`CFn)mp6~l1ghV>_Y z_?Pd32BxzAw$E*~VPP;aQ=Ef9m|kA6y!a)5Xh*Tg!V9*jADcG`rrseEARD)?VR74? zM}GR3|LrQSd{I9A#4(Ax!ErB^= zj5c)*IiN4yaDV^BC%<=f7QMSX^og%uJhj&^7K*c@VLMH|H<7s#>xKQWb8pP_ zfHrjv!@#W^T6z3udy&%jfb4mM?*X~x_Rnvf9mlaqG)<-oplDsF2Vm}C+mfTRWbSsJ z(DYxkx9si_&RvZ-50tqeQ=&|^t0OnvwsH2|@Q3dG{5QAd@aSR{C#sE^zzhW!EdBY5 zZ&@L8Yn=Lsb53CQ8xWRk|5-sj%w2;yF0G;|rVAIw$8WoH^VD-!TMqzm*GK-~m1i$> zjvz>ff{OvbU45XPZV=3runSZyy2U$O#?F3dyAoA2)^Xp_58VB+55N4(lUG#$ ziB3;q>+{M?# zgYWy`XCMCXuYYwFFTPto_LUc(xiHymQf(UBm~eZ=FGTQg4gxPna0YR&i-k){=uCu; zjtdM_O_EH;^}$;v0XVykchSR}+XSWl8%ipOyWeOF->!)V;28kF!(zA zuX~J$h=i>G&M?t|O;up+*(pJ48&QAF3;f~vX!7rREGS8>oL{m(! zovZHt*n=-Wb5%wZ9lQ6DGp}q`qbQA8g2iy?ZjRuB&$Ejn7JvQgV&N`t*eM+rf|?|) z>t^l!AFR$_Eq2OV?s$0f?6?^x=}>SX9J*{4be|vbjXa>K3pBg#an4R!{=Orj2vZBm z%%Jm!Cfn8fe&@~$r>}~O{Ci*g&Qp(_oov)OIjS;AvHBAV7sR?&J~fAGY;ub#XHl|*~;rm_cw z*Q4C`$*-P0d8r!ZMktu;5nQnPr#{>qB~}M>uZx6p0V14P{T&w0e&KSwbeBH7u7ISa zE>jiV9@Te!^nojgg~v`jeEzlVW;^FcyAoNOS?jagf9BRqqg%_e0~8VFZ~cXbJO9(^ zs(1GbJLk|$EvB?~!w2dMFTbP3FUrlg{r>1;=FKq?u$(8JRyOX81kU;R^LA4EbZ+T$ z`D5rd$l_%WJAT=GByd4F-M`yhvc@J|SuFg_Bi}mp^!aMDNwrEcRkXQXF9m zqz?QDAU|CSkWTG^&Rm?r;cSmAJn0_qJRlt!=3Sx9q}jv5>r?iC@Vb-xKKa!%Cv#_X zE{(y?>YopMb!T-N@R@~0Av0-DSu>XcVBK3`(Y9TJLByq#J}0|XqUMyLs>t@JzWbvO zyz=Z7IPJ$yJbeE2s2+>9C^+?rrw;KhC^MX>NQk9_Nu76nBTsDQRX@@WguT;w07Aeg!3fe>lV7i?ddLSq*n>2R?{z=cCH z7fP9`dTIT(q_H-SV5(YAnp;oY`|8Q7m^$5)w;_8#czwx7fBze=y?Ch}MQNsO5?v|a zT=^eP{{fgD-Ki&(Pk6owrVpmBViyscp(xD3VtzjTJUj2X&Ly2MOUy%jGIz15>SWyf z?q?r*`pI{cFTClYFPvLI!PX~+u8(={11@_%Ggt4;z7|8KbC=qiBkAjlb&Z!I2X47_ zeD2UY`6tg$S`;)DP@5Kr;&hHk7wDa>rp3G|7B1r7d^~gt zlR1vs#YemIg^S3C%QnI;`(}R92^grwI^Oxv11~?fmoL1IWDf|hBl+?-zw_*`FXYUJ zbo?N;TW>&jxy_DxKBe7(pPIDocj%5iWovgDKAqbBxNzsqqGG!^LAXe~vDi?R-67G9 zt+@FP3P$ey%paV3=~6XH5>;i<7o3la&bcgexxuA8-_DfS!fK}e@$5gC{%EH0jI5W!5wMi_si%ge2MZvkk;MqmL(?aOn z#KlnHax`@3mB0LwEk0>ow02jhS&Z@a2k(FNg?Hc#+0pSvW)h!M#X^1TG~UtTIpyGI zXAlq~&&~o8%^uIao*l=<1F~Qa?AQ}?KY1PdpbMRwnQ2`$pZYf+dFsh`qrGHLE=Tr& z@H&#DM<jWZ|Th8{ltm2W)r)cMI)lv-^uFSy_n!;&vJ7r&a_i^~^(cj@l{#5csk zxu3j&!@R`p+J=i`OgEpn`{GM)Cop*LC%rzkbGG;jOcmbMcI7UB!n!{m=_fy&Y%h?t4E!IzNdMk)*1i zHf^QFxeYK&{!RCJ#zF$%4()gW1;HUYLPm7?^|>JGQgRUI^|31=zDX#dE2$E_G-@uM zdpoCNPp*dS0pax`cRcWgt@D$n5{)fQ{#*uVX7W#u;_N=}Ox-yw1O&{-o(Xx*+Qrsc zT#Sd#AL;CW!W=X#AY$hTbsu|2CFzWaL{)CN=kBvFz2#_Fg-1slbuI|BHaNUw_|F<4 z7xIF0C^#P}g!u?!_k3D4H1A2yzkeAEcXbRGWTy{cfB-wY=%WU;F0C zXD?Qx%$&Jf&D3ri1LlAp=l$P8Dw|Hro#!le?Kt>U8Pc zTMiX`_>*6`^xCKyw-JIiSh7f-2Qwq5Jqy#|2X($6BND>&I53e%a)b`&j|t?HLbLQ> z4*uivu0WX9ZZGL%)?D9xxG7;1LR(vQ<861GeRZ$b{<@GoAiOT*!@u{{bEh&{@N{m# zv|n)H>Yo)i%w_VYB>>d*NI61YKHjrT$@F*4f;mel_bc?_Tohpo*- zxL{Px-S|6_rc0$Eb5C|Fp_+f3+38GGZ@lA<^QYbd=fGFK@vT>$yI5^CEz$fgr=#5x zvm&7OP++(4*(t~m9HA%jM2^UJ$7Fg~+UAN~Pr#gmIQ4*S;fLLW#WBC#-)zR*rlPk$ zaNjHMBv!m9S4j4N@Vbx?j#pbvthH?pv-xuHg<9}@&CSvt?da@$!n4^6j%MzlLu90x z6EJ_m=l{3E-kiY$+BvgU>1bjBYo2>9VUu9(v@fFTHrF8pRazSi$9p=mHQf zR{6tX;A)BvIIqP8T%1Ks=M=KA(p@#P_+U;0i#EaZ)!h8AsyE(s$Hps{n=HKNV_(=f zv)xSEVUs#*mYA~%7J+cq2fi2*>~=_w4Fb`UZ8R&Dg!zQ&8&=@%k}`xY^f%vEv49jU zF|LT-`|ARraJuD8zqjBw4Uix(p(FB(UyjHTEyPY1 z6U&Q>UwCXgUU@^AHs2VS#gr~yHSUEyxqR6J!fP*gKKS{q3zM80w5~FKu^fDQyUqK8 zt=&p6%lzd$2O~Pd_F&H)Z|-6~IDh-k%k+%m?yq+Te=h2^X#6A2MMn`3%uGLU;;u87 zmm!P(==P-?6zv$)Y{4y_0pVOT$a2m9eB^Y_)mymNX8FSDZ(YQ~c0D_>ZJE?(NgK2G z%}s>Lze-d;{^|Q)eCnAu)x#rS`^HNzT&hMf)pHSoS;Ba_-r2^O+aa(R9&F7cMw~)m zHj+BqsB1IFWy|6XY@=@ByUDIqq}>Ro{2(T|boR0uOFr_cFXdXH6m?oYW^?AzG%_-E z2NxP70O$5UF=8MJyP=>%a@3xe95|WojxO4SszqgxY<^avS=;)Fwn}hW&^g_@O8A+(Muy4uqb_P3?ne8TFiX zFw1_=9hT_?=-0Okb_gz{BMj`JPdxDa(|cX^*HZR?@ES|#zi)e^jzfaO}x`C+9qGW~hXd_5SjS%+aO?G$fA zG$6S7&O6S%X;iRxY`oQ^S}nmmhrl9m&r)D8_4#1QmznhuEJ7e6bs<2U{;q{}wb$B$ zcewLzUtHYRhp%^k>hpha=G0c5eV}f%Y&TzU83(?(39G^*Y+w%uchn(;kA^HefBHoPj6=e<*7Tk)Ec#D^)EPr(3G`6oNI zG551stT=z_WVU_wjr`-#KfYia&F_i@gJAm4qJ=bj&_zTuBv9TM**ro=#54_-&O=~( z$J^qczPr44EfHF_3~c95r`o_y6=1jAdHdPdH;=yh^{>D3;$}VSf+ezCBQq`eT8N9z z;=S{o66A?IcGWS2p15QV%ms5`3QV5Z6LIGqw=>7O@750Aone|TtZP03uwz5mQr!#y zOoIfiHFoC%_q_c4vv05~_T;JxUF#3>`JzNOPFGs?|fidbIm{zxuH!$>Afv_L<$IgU%MILF;)* zZkpKmI9{GAuSc@%e;SROp_%Mfq$WUY~vYE=+`EY(VZa1#=#6yA5 zdPM!HK0eGXURtG%j*DezrR(BOzwhV=fut=va6SZ5em%9r2<@uXQvKs=ml0YIU% z?XM3nzw+jjMDgk?SBJ$n>UTv%?#FL`bmvy)s_l)$NQL~?PlIeWMC7&v=ff^%`F=vy&5FjPK>dvv+l0;zxa_~ev&92J-nXxRja{riohe9@y>2ryU52OsFgG>eDiDZ32(SvBb$`A8 zk3RBGZWYCY2iNo7!@X1pMB>GXPZex z8WAhF|EtdOt=?r77ru3xaFIrWY8eTs)kA&!==!6dz9lI92)`|h4~Zh?CST{#t&au7yu1CAo!)oLhfhqX6@ zo;U%t>b##HJ|QUl2mkmJhwG}?+s?=TJMbqw;c8V;COo zKDq=9XHfW_ci;UlKle|D;Yr&b9WL5*Uw`4~jP4DupXvCSUNZ0zeO71NT^+u0o7VgG zE7$w$x#6Nq@NhE$w?=XE1EAf;)oQdd9cFlbIsMoFp^)=;5yJt3^17=2P5acURYV!(rpr3LD=RX~a6j z!ooaE!^i)JU;5C8KUj*O`_2B=9fzAYAM^3&S>KlGmadmy+tt0QT3SIS0*HCRfBKVz<(b7Oa_T{U3LtJ-ePU(;fUC!cKl%MH6Mgxx zt5r=6X>MH8MgZ3ZVl5*`ZKg!$;y0}8Cit^>?EYEMpYSL;boSaWGIb^*-DlctXzUEkalSC95uHBr%4LQDjJd9@8Fotb4<^yYG9 zp2K``N(`iGuYLFNfA?Sg&w9|qtp1jb*AI)Uw0 z>w|~KLE$Gq{pl}%@j-_VQ=Snzy3XUp%|~e#9Lw9LH`3uR0C4qa|G)e940R9}NrFomd=6gVD#u-DXHJ0x&W)Q=RwoD-Ukj6{qzS*2xe)oAvn7A+&#_ zJ{DWJ{>4-_eB+tkK5>#-5_^G#0o8!23ae@asG+J=m;%}w_gh6eH54z8I(P53(swu4 zZHl6uc|YuGsyrX&*B%}p_3NvH&Stg*s~PZee9Lr;6c1y5m_vJ@87D)fJLt(n#&42$_KJx$koBy-@*)M0yi61xE)1B|Ge*^FwCeFaF(-6JzB`*8uc7xVVS`_4CHx4;9P zkA;@;W%rH9Glkbz`=i%={lUH-s->H_MB>5SxweH&$AvpBP)=8=Iec#KD@?!xq{2|^ zU^Z9vGcv2rX4SMp6{avO$0Q@uTlPkx$9PiMx*V)Lzz~oBOdW393w9-9y6vpUzS$GiR#{i0ORaj zyE=U4GatWsd8hSuuahBs2J6+=clA)sqD-c#V28hM^C;IQq0>9P=N?HYf&ywV!)!L2 z9n@yE*=#m-qr0s0m>TKVpYN#^|Pfindzt*=7#C&d@b-z1&^w*Y>nFnv|qc&vy z{*YTLGg@A-D}?EN^JcwPpK~cn0MrncU~vGBg1@y<=^5kJrs0X`+;L8*dw?!Jp6ikO zfAx63uA4pj!?!TBo!dmK-QvID7u%d9HPm#8s#QkRM>=Ld;Gn)R_>wC0HnYUN(KX%^zv}X#qk62-|ssFpvy03Mw zdT3v!wRw}B6=5ANN^TkcnWG(ygBhN;!V{Ms9D)lza=Z__#%!e_8{`>IvV zJ#zp)gx8`vqDRw?l-;6Mx}c;b;*2Pj9TetX?ZI@;uWB~u@m9c6@vZ&b-s|tf!5fZ0 zcj#TSKzw928Ys0y0B?3$?{H94BLkTc^*XN)HK==wqZiM(u(OEVo?NtH_VP88*dmQo zm&Ytx{e!-DqQ73gAr|g!cEZ+BcqxKf>CRECc{=Xmf!@+;`W1sr?e5iG<0CcXV zs)xGx1h?sqwH;dHqI}~QdTq5h41K0&v4zytrra>(w?u^NJJKiY7KdP6+Pe4zltA%= zM^QWa#+!Sc)l|bV0&K2m`0&cc97(?4Gwu1_48T^fIV!9g)KGzH$k4~J({)6+v@5K3 z#mXMPRcMSG!SM>i@QkUc&4>9{KM_7b!-xH+k>Kq_aceNXz8U?ygsoA6!j!@Zn4vRl zue!6kSKXVs3EYPv)EP^ltYmB4_!zdi;kn+pU$@+&V_Ob`s_yqEL--8V$q+v6^_kCn za-Q{YwF7{vy01_(HI}2}j2n7{q7*ZK;n?LT3tg6OZ+f*h!~9^^gob)Q*VbU%k+-`} z6W)vtm(SMOs%Bc!2)RZ!(^?O^FoX}@yqXX7aJ?tM4t2hot*Xw-3oeQ-?ROljEdksr zP&l?;ttVx5UB@u+O^CHw)}!~m1?aoYQ1u~E`?O6hM{s<79q8z8cc@kCeg>e2T6eRf zmg^6;+8DT1y>jQ%FfE2K@3rf6g;lcJ!2`Xn&#!2r=w6K|XwGhgiG1t7M}j&MT88PS zb*@)effF3|vsSgL0BrW;cD1T7TL;8_D7HMn4J(*VfQ1tfu7J&p<*N}Fx)p>SU^4<8 zt(i?vYrO338wkoRXl<8BUhdJ6C<3N1GqrlCpZw%U>9n5iIvK*Jy}tFWSL$IV0P}2W z#DIaBV4&8~a8rqNW~PNQ$NoN{i}tJ?z4-x-Vc~95#J|0XI{Ncfyb3j~>W1*MpZP>RxNE3@ z7dmS+PY84OQq4&B`GT9#_i{7{O3M*&*RVx_ds~Huv!kPVQv7dibyBD~9B=i-NA?d# zkC)vTWmKlMzWL@UP589eseR&UufzVJGmWEMJ=lj=&j4VDDy0w`OIdlBZH#=VykG=& zoeYk`br2~?Tw#HiN%6~hZPj+-*#Xj);8 z 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 literal 142421 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 Nqa?2mua&hx{159}a3BBx literal 115904 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

!iDbTF#0lXkbZ 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 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-Roughness-vs-Coat-Roughness.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-Roughness-vs-Coat-Roughness.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ea12554a36898907bed41d37493c0f569a6870 GIT binary patch literal 100740 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 literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/config.json b/packages/tools/tests/test/visualization/config.json index e39dfe30045..148d60ecbdc 100644 --- a/packages/tools/tests/test/visualization/config.json +++ b/packages/tools/tests/test/visualization/config.json @@ -2779,22 +2779,42 @@ }, { "title": "OpenPBR IBL Specular IOR vs Coat IOR", - "playgroundId": "#GRQHVV#28", + "playgroundId": "#GRQHVV#39", "excludedEngines": ["webgl1"] }, { - "title": "OpenPBR IBL Metal vs Coat IOR", - "playgroundId": "#GRQHVV#29", + "title": "OpenPBR IBL Metalness vs Coat IOR", + "playgroundId": "#GRQHVV#38", "excludedEngines": ["webgl1"] }, { "title": "OpenPBR IBL Specular IOR vs Coat Weight", - "playgroundId": "#GRQHVV#30", + "playgroundId": "#GRQHVV#40", "excludedEngines": ["webgl1"] }, { "title": "OpenPBR IBL Specular Roughness vs Coat Roughness", - "playgroundId": "#GRQHVV#31", + "playgroundId": "#GRQHVV#41", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR Analytic Lights Specular Roughness vs Coat Roughness", + "playgroundId": "#GRQHVV#42", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR Analytic Lights Specular Weight vs Metalness", + "playgroundId": "#GRQHVV#34", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR Analytic Lights Specular IOR vs Coat Weight", + "playgroundId": "#GRQHVV#35", + "excludedEngines": ["webgl1"] + }, + { + "title": "OpenPBR Analytic Lights Specular IOR vs Coat IOR", + "playgroundId": "#GRQHVV#36", "excludedEngines": ["webgl1"] } ] From c229e2975ba03386182672dfad1a5512fb6cf3ab Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 4 Aug 2025 16:19:50 -0700 Subject: [PATCH 30/45] WebGPU OpenPBR base layer support for direct lighting --- .../openpbrBlockAmbientOcclusion.fx | 30 -- .../ShadersInclude/openpbrDirectLighting.fx | 5 +- .../openpbrEnvironmentLighting.fx | 127 ++++++++ .../ShadersInclude/openpbrIblFunctions.fx | 26 +- .../openpbrNormalMapFragment.js | 63 ---- .../openpbrNormalMapFragment.js.map | 1 - .../openpbrNormalMapFragmentFunctions.js | 42 --- .../openpbrNormalMapFragmentFunctions.js.map | 1 - .../openpbrNormalMapFragmentMainFunctions.js | 72 ----- ...enpbrNormalMapFragmentMainFunctions.js.map | 1 - .../ShadersInclude/openpbrNormalMapVertex.js | 16 - .../openpbrNormalMapVertex.js.map | 1 - .../openpbrNormalMapVertexDeclaration.js | 16 - .../openpbrNormalMapVertexDeclaration.js.map | 1 - .../dev/core/src/Shaders/openpbr.fragment.fx | 187 +----------- .../ShadersInclude/openPbrUboDeclaration.fx | 2 +- .../ShadersInclude/openpbrBaseLayerData.fx | 138 +++++++++ .../openpbrBlockAlbedoOpacity.fx | 116 ------- .../openpbrBlockAmbientOcclusion.fx | 31 -- .../openpbrBlockFinalLitComponents.fx | 54 ---- .../openpbrBlockGeometryInfo.fx | 35 --- .../ShadersInclude/openpbrBlockNormalFinal.fx | 19 ++ .../ShadersInclude/openpbrBlockReflectance.fx | 36 --- .../openpbrBlockReflectivity.fx | 137 --------- .../ShadersInclude/openpbrCoatLayerData.fx | 65 ++++ .../openpbrConductorReflectance.fx | 17 ++ .../openpbrDielectricReflectance.fx | 53 ++++ .../ShadersInclude/openpbrDirectLighting.fx | 93 ++++++ .../openpbrDirectLightingInit.fx | 93 ++++++ .../openpbrEnvironmentLighting.fx | 131 ++++++++ .../ShadersInclude/openpbrGeometryInfo.fx | 37 +++ .../ShadersInclude/openpbrIblFunctions.fx | 272 +++++++++-------- .../openpbrNormalMapFragment.js | 63 ---- .../openpbrNormalMapFragment.js.map | 1 - .../openpbrNormalMapFragmentFunctions.js | 42 --- .../openpbrNormalMapFragmentFunctions.js.map | 1 - .../openpbrNormalMapFragmentMainFunctions.js | 51 ---- ...enpbrNormalMapFragmentMainFunctions.js.map | 1 - .../core/src/ShadersWGSL/openpbr.fragment.fx | 284 +++++------------- 39 files changed, 1022 insertions(+), 1339 deletions(-) delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js delete mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockNormalFinal.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrConductorReflectance.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrGeometryInfo.fx delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js delete mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx deleted file mode 100644 index c0a25e633b3..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx +++ /dev/null @@ -1,30 +0,0 @@ -struct ambientOcclusionOutParams -{ - vec3 ambientOcclusionColor; -#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) - vec3 ambientOcclusionColorMap; -#endif -}; - -ambientOcclusionOutParams ambientOcclusionBlock( -#ifdef AMBIENT_OCCLUSION - in vec3 ambientOcclusionFromTexture, - in vec2 ambientOcclusionInfos -#endif -) -{ - ambientOcclusionOutParams outParams; - vec3 ambientOcclusionColor = vec3(1., 1., 1.); - - #ifdef AMBIENT_OCCLUSION - ambientOcclusionColor = vec3(ambientOcclusionFromTexture.r * ambientOcclusionInfos.y); - - #if DEBUGMODE > 0 - outParams.ambientOcclusionColorMap = ambientOcclusionFromTexture; - #endif - #endif - - outParams.ambientOcclusionColor = ambientOcclusionColor; - - return outParams; -} diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx index badfea3b6e4..ea88a610596 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx @@ -48,13 +48,12 @@ slab_metal = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, baseConductorReflectance.F0, baseConductorReflectance.F90); #else { - vec3 coloredFresnel; // For OpenPBR, we use the F82 specular model for metallic materials and mix with the // usual Schlick lobe. #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) - coloredFresnel = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90, specular_roughness); + vec3 coloredFresnel = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90, specular_roughness); #else - coloredFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90); + vec3 coloredFresnel = fresnelSchlickGGX(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90); #endif #ifdef ANISOTROPIC diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx new file mode 100644 index 00000000000..20ac47f68ff --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx @@ -0,0 +1,127 @@ +// _____________________________ Base Diffuse Layer IBL _______________________________________ +#ifdef REFLECTION + // Pass in a vector to sample teh irradiance with (to handle reflection or ) + vec3 baseDiffuseEnvironmentLight = sampleIrradiance( + normalW + #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 + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + #endif + #endif + , vReflectionInfos + , viewDirectionW + , base_diffuse_roughness + , base_color + ); + + // _____________________________ Base Specular Layer IBL _______________________________________ + + #ifdef REFLECTIONMAP_3D + vec3 reflectionCoords = vec3(0., 0., 0.); + #else + vec2 reflectionCoords = vec2(0., 0.); + #endif + reflectionCoords = createReflectionCoords(vPositionW, normalW); + float specularAlphaG = specular_roughness * specular_roughness; + vec3 baseSpecularEnvironmentLight = sampleRadiance(specularAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , baseGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + ); + + baseSpecularEnvironmentLight = mix(baseSpecularEnvironmentLight.rgb, baseDiffuseEnvironmentLight, specularAlphaG); + + vec3 coatEnvironmentLight = vec3(0., 0., 0.); + if (coat_weight > 0.0) { + #ifdef REFLECTIONMAP_3D + vec3 reflectionCoords = vec3(0., 0., 0.); + #else + vec2 reflectionCoords = vec2(0., 0.); + #endif + reflectionCoords = createReflectionCoords(vPositionW, coatNormalW); + float coatAlphaG = coat_roughness * coat_roughness; + coatEnvironmentLight = sampleRadiance(coatAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , coatGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , vReflectionFilteringInfo + #endif + ); + } + + // ______________________________ IBL Fresnel Reflectance ____________________________ + + // Dielectric IBL Fresnel + // The colored fresnel represents the % of light reflected by the base specular lobe + // The non-colored fresnel represents the % of light that doesn't penetrate through + // the base specular lobe. i.e. the specular lobe isn't energy conserving for coloured specular. + float dielectricIblFresnel = getReflectanceFromBRDFLookup(vec3(baseDielectricReflectance.F0), vec3(baseDielectricReflectance.F90), baseGeoInfo.environmentBrdf).r; + vec3 dielectricIblColoredFresnel = getReflectanceFromBRDFLookup(baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, baseGeoInfo.environmentBrdf); + + // Conductor IBL Fresnel + vec3 conductorIblFresnel = conductorIblFresnel(baseConductorReflectance, baseGeoInfo.NdotV, specular_roughness, baseGeoInfo.environmentBrdf); + + // Coat IBL Fresnel + float coatIblFresnel = 0.0; + if (coat_weight > 0.0) { + coatIblFresnel = getReflectanceFromBRDFLookup(vec3(coatReflectance.F0), vec3(coatReflectance.F90), coatGeoInfo.environmentBrdf).r; + } + + + vec3 slab_diffuse_ibl = vec3(0., 0., 0.); + vec3 slab_glossy_ibl = vec3(0., 0., 0.); + vec3 slab_metal_ibl = vec3(0., 0., 0.); + vec3 slab_coat_ibl = vec3(0., 0., 0.); + + slab_diffuse_ibl = baseDiffuseEnvironmentLight * vLightingIntensity.z; + slab_diffuse_ibl *= aoOut.ambientOcclusionColor; + + // Add the specular environment light + slab_glossy_ibl = baseSpecularEnvironmentLight * vLightingIntensity.z; + + // _____________________________ Metal Layer IBL ____________________________ + slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; + + // _____________________________ Coat Layer IBL _____________________________ + if (coat_weight > 0.0) { + slab_coat_ibl = coatEnvironmentLight * vLightingIntensity.z; + } + + // TEMP + vec3 slab_subsurface_ibl = vec3(0., 0., 0.); + vec3 slab_translucent_base_ibl = vec3(0., 0., 0.); + vec3 slab_fuzz_ibl = vec3(0., 0., 0.); + + slab_diffuse_ibl *= base_color.rgb; + + // _____________________________ IBL Material Layer Composition ______________________________________ + #define CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION + vec3 material_opaque_base_ibl = mix(slab_diffuse_ibl, slab_subsurface_ibl, subsurface_weight); + vec3 material_dielectric_base_ibl = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); + vec3 material_dielectric_gloss_ibl = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3(1.0), specular_color); + vec3 material_base_substrate_ibl = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); + vec3 material_coated_base_ibl = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3(1.0)); + material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); + +#endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx index 803d7f1b495..a338a332dc3 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx @@ -5,7 +5,7 @@ vec3 sampleIrradiance( in vec3 surfaceNormal #if defined(NORMAL) && defined(USESPHERICALINVERTEX) - , in vec3 vEnvironmentIrradiance + , in vec3 vEnvironmentIrradianceSH #endif #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) , in mat4 iblMatrix @@ -34,8 +34,8 @@ vec3 environmentIrradiance = vec3(0., 0., 0.); #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) - vec3 irradianceVector = vec3(iblMatrix * vec4(surfaceNormal, 0)).xyz; - vec3 irradianceView = vec3(iblMatrix * vec4(viewDirectionW, 0)).xyz; + vec3 irradianceVector = (iblMatrix * vec4(surfaceNormal, 0)).xyz; + vec3 irradianceView = (iblMatrix * vec4(viewDirectionW, 0)).xyz; #if !defined(USE_IRRADIANCE_DOMINANT_DIRECTION) && !defined(REALTIME_FILTERING) // Approximate diffuse roughness by bending the surface normal away from the view. #if BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LAMBERT && BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LEGACY @@ -56,7 +56,7 @@ #endif #ifdef USESPHERICALFROMREFLECTIONMAP #if defined(NORMAL) && defined(USESPHERICALINVERTEX) - environmentIrradiance = vEnvironmentIrradiance; + environmentIrradiance = vEnvironmentIrradianceSH; #else #if defined(REALTIME_FILTERING) environmentIrradiance = irradiance(reflectionSampler, irradianceVector, vReflectionFilteringInfo, diffuseRoughness, surfaceAlbedo, irradianceView @@ -182,22 +182,6 @@ // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection reflectionLOD = reflectionLOD * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z; - #ifdef LODINREFLECTIONALPHA - // Automatic LOD adjustment to ensure that the smoothness-based environment LOD selection - // is constrained to appropriate LOD levels in order to prevent aliasing. - // The environment map is first sampled without custom LOD selection to determine - // the hardware-selected LOD, and this is then used to constrain the final LOD selection - // so that excessive surface smoothness does not cause aliasing (e.g. on curved geometry - // where the normal is varying rapidly). - - // Note: Shader Model 4.1 or higher can provide this directly via CalculateLevelOfDetail(), and - // manual calculation via derivatives is also possible, but for simplicity we use the - // hardware LOD calculation with the alpha channel containing the LOD for each mipmap. - float automaticReflectionLOD = UNPACK_LOD(sampleReflection(reflectionSampler, reflectionCoords).a); - float requestedReflectionLOD = max(automaticReflectionLOD, reflectionLOD); - #else - float requestedReflectionLOD = reflectionLOD; - #endif #ifdef REALTIME_FILTERING environmentRadiance = vec4(radiance(alphaG, reflectionSampler, reflectionCoords, vReflectionFilteringInfo), 1.0); #else @@ -213,7 +197,7 @@ #endif // _____________________________ Levels _____________________________________ - environmentRadiance.rgb *= vReflectionInfos.x; + environmentRadiance.rgb *= vec3(vReflectionInfos.x); return environmentRadiance.rgb; } diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js deleted file mode 100644 index 779073df38d..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js +++ /dev/null @@ -1,63 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapFragment"; -const shader = `vec2 uvOffset=vec2(0.0,0.0); -#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) -#ifdef NORMALXYSCALE -float normalScale=1.0; -#elif defined(GEOMETRY_NORMAL) -float normalScale=vGeometryNormalInfos.y; -#else -float normalScale=1.0; -#endif -#if defined(TANGENT) && defined(NORMAL) -mat3 TBN=vTBN; -#elif defined(GEOMETRY_NORMAL) -vec2 TBNUV=gl_FrontFacing ? vGeometryNormalUV : -vGeometryNormalUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vTangentSpaceParams); -#else -vec2 TBNUV=gl_FrontFacing ? vDetailUV : -vDetailUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vec2(1.,1.)); -#endif -#elif defined(ANISOTROPIC) -#if defined(TANGENT) && defined(NORMAL) -mat3 TBN=vTBN; -#else -vec2 TBNUV=gl_FrontFacing ? vMainUV1 : -vMainUV1;mat3 TBN=cotangent_frame(normalW,vPositionW,TBNUV,vec2(1.,1.)); -#endif -#endif -#ifdef PARALLAX -mat3 invTBN=transposeMat3(TBN); -#ifdef PARALLAXOCCLUSION -uvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,vGeometryNormalUV,vGeometryNormalInfos.z); -#else -uvOffset=parallaxOffset(invTBN*viewDirectionW,vGeometryNormalInfos.z); -#endif -#endif -#ifdef DETAIL -vec4 detailColor=texture2D(detailSampler,vDetailUV+uvOffset);vec2 detailNormalRG=detailColor.wy*2.0-1.0;float detailNormalB=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));vec3 detailNormal=vec3(detailNormalRG,detailNormalB); -#endif -#ifdef GEOMETRY_NORMAL -#ifdef OBJECTSPACE_NORMALMAP -#define CUSTOM_FRAGMENT_BUMP_FRAGMENT -normalW=normalize(texture2D(geometryNormalSampler,vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3(normalMatrix)*normalW); -#elif !defined(DETAIL) -normalW=perturbNormal(TBN,texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz,vGeometryNormalInfos.y); -#else -vec3 bumpNormal=texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz*2.0-1.0; -#if DETAIL_NORMALBLENDMETHOD==0 -detailNormal.xy*=vDetailInfos.z;vec3 blendedNormal=normalize(vec3(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z)); -#elif DETAIL_NORMALBLENDMETHOD==1 -detailNormal.xy*=vDetailInfos.z;bumpNormal+=vec3(0.0,0.0,1.0);detailNormal*=vec3(-1.0,-1.0,1.0);vec3 blendedNormal=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal; -#endif -normalW=perturbNormalBase(TBN,blendedNormal,vGeometryNormalInfos.y); -#endif -#elif defined(DETAIL) -detailNormal.xy*=vDetailInfos.z;normalW=perturbNormalBase(TBN,detailNormal,vDetailInfos.z); -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStore[name]) { - ShaderStore.IncludesShadersStore[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragment = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragment.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map deleted file mode 100644 index 59012042574..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragment.js","sourceRoot":"","sources":["openpbrNormalMapFragment.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,0BAA0B,CAAC;AACxC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragment\";\nconst shader = `vec2 uvOffset=vec2(0.0,0.0);\n#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL)\n#ifdef NORMALXYSCALE\nfloat normalScale=1.0;\n#elif defined(GEOMETRY_NORMAL)\nfloat normalScale=vGeometryNormalInfos.y;\n#else\nfloat normalScale=1.0;\n#endif\n#if defined(TANGENT) && defined(NORMAL)\nmat3 TBN=vTBN;\n#elif defined(GEOMETRY_NORMAL)\nvec2 TBNUV=gl_FrontFacing ? vGeometryNormalUV : -vGeometryNormalUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vTangentSpaceParams);\n#else\nvec2 TBNUV=gl_FrontFacing ? vDetailUV : -vDetailUV;mat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,TBNUV,vec2(1.,1.));\n#endif\n#elif defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nmat3 TBN=vTBN;\n#else\nvec2 TBNUV=gl_FrontFacing ? vMainUV1 : -vMainUV1;mat3 TBN=cotangent_frame(normalW,vPositionW,TBNUV,vec2(1.,1.));\n#endif\n#endif\n#ifdef PARALLAX\nmat3 invTBN=transposeMat3(TBN);\n#ifdef PARALLAXOCCLUSION\nuvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,vGeometryNormalUV,vGeometryNormalInfos.z);\n#else\nuvOffset=parallaxOffset(invTBN*viewDirectionW,vGeometryNormalInfos.z);\n#endif\n#endif\n#ifdef DETAIL\nvec4 detailColor=texture2D(detailSampler,vDetailUV+uvOffset);vec2 detailNormalRG=detailColor.wy*2.0-1.0;float detailNormalB=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));vec3 detailNormal=vec3(detailNormalRG,detailNormalB);\n#endif\n#ifdef GEOMETRY_NORMAL\n#ifdef OBJECTSPACE_NORMALMAP\n#define CUSTOM_FRAGMENT_BUMP_FRAGMENT\nnormalW=normalize(texture2D(geometryNormalSampler,vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3(normalMatrix)*normalW);\n#elif !defined(DETAIL)\nnormalW=perturbNormal(TBN,texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz,vGeometryNormalInfos.y);\n#else\nvec3 bumpNormal=texture2D(geometryNormalSampler,vGeometryNormalUV+uvOffset).xyz*2.0-1.0;\n#if DETAIL_NORMALBLENDMETHOD==0 \ndetailNormal.xy*=vDetailInfos.z;vec3 blendedNormal=normalize(vec3(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z));\n#elif DETAIL_NORMALBLENDMETHOD==1 \ndetailNormal.xy*=vDetailInfos.z;bumpNormal+=vec3(0.0,0.0,1.0);detailNormal*=vec3(-1.0,-1.0,1.0);vec3 blendedNormal=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal;\n#endif\nnormalW=perturbNormalBase(TBN,blendedNormal,vGeometryNormalInfos.y);\n#endif\n#elif defined(DETAIL)\ndetailNormal.xy*=vDetailInfos.z;normalW=perturbNormalBase(TBN,detailNormal,vDetailInfos.z);\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragment = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js deleted file mode 100644 index b1cfd4b690e..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js +++ /dev/null @@ -1,42 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -import "./samplerFragmentDeclaration"; -const name = "openpbrNormalMapFragmentFunctions"; -const shader = `#if defined(GEOMETRY_NORMAL) -#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) -#endif -#if defined(DETAIL) -#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) -#endif -#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) -const float minSamples=4.;const float maxSamples=15.;const int iMaxSamples=15;vec2 parallaxOcclusion(vec3 vViewDirCoT,vec3 vNormalCoT,vec2 texCoord,float parallaxScale) {float parallaxLimit=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;vec2 vOffsetDir=normalize(vViewDirCoT.xy);vec2 vMaxOffset=vOffsetDir*parallaxLimit;float numSamples=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));float stepSize=1.0/numSamples;float currRayHeight=1.0;vec2 vCurrOffset=vec2(0,0);vec2 vLastOffset=vec2(0,0);float lastSampledHeight=1.0;float currSampledHeight=1.0;bool keepWorking=true;for (int i=0; icurrRayHeight) -{float delta1=currSampledHeight-currRayHeight;float delta2=(currRayHeight+stepSize)-lastSampledHeight;float ratio=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;} -else -{currRayHeight-=stepSize;vLastOffset=vCurrOffset; -#ifdef PARALLAX_RHS -vCurrOffset-=stepSize*vMaxOffset; -#else -vCurrOffset+=stepSize*vMaxOffset; -#endif -lastSampledHeight=currSampledHeight;}} -return vCurrOffset;} -vec2 parallaxOffset(vec3 viewDir,float heightScale) -{float height=texture2D(geometryNormalSampler,vGeometryNormalUV).w;vec2 texCoordOffset=heightScale*viewDir.xy*height; -#ifdef PARALLAX_RHS -return texCoordOffset; -#else -return -texCoordOffset; -#endif -} -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStore[name]) { - ShaderStore.IncludesShadersStore[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragmentFunctions = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragmentFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map deleted file mode 100644 index 7bb46666b4c..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragmentFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,8BAA8B,CAAC;AAEtC,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\nimport \"./samplerFragmentDeclaration\";\n\nconst name = \"openpbrNormalMapFragmentFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL)\n#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal)\n#endif\n#if defined(DETAIL)\n#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail)\n#endif\n#if defined(GEOMETRY_NORMAL) && defined(PARALLAX)\nconst float minSamples=4.;const float maxSamples=15.;const int iMaxSamples=15;vec2 parallaxOcclusion(vec3 vViewDirCoT,vec3 vNormalCoT,vec2 texCoord,float parallaxScale) {float parallaxLimit=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;vec2 vOffsetDir=normalize(vViewDirCoT.xy);vec2 vMaxOffset=vOffsetDir*parallaxLimit;float numSamples=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));float stepSize=1.0/numSamples;float currRayHeight=1.0;vec2 vCurrOffset=vec2(0,0);vec2 vLastOffset=vec2(0,0);float lastSampledHeight=1.0;float currSampledHeight=1.0;bool keepWorking=true;for (int i=0; icurrRayHeight)\n{float delta1=currSampledHeight-currRayHeight;float delta2=(currRayHeight+stepSize)-lastSampledHeight;float ratio=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;}\nelse\n{currRayHeight-=stepSize;vLastOffset=vCurrOffset;\n#ifdef PARALLAX_RHS\nvCurrOffset-=stepSize*vMaxOffset;\n#else\nvCurrOffset+=stepSize*vMaxOffset;\n#endif\nlastSampledHeight=currSampledHeight;}}\nreturn vCurrOffset;}\nvec2 parallaxOffset(vec3 viewDir,float heightScale)\n{float height=texture2D(geometryNormalSampler,vGeometryNormalUV).w;vec2 texCoordOffset=heightScale*viewDir.xy*height;\n#ifdef PARALLAX_RHS\nreturn texCoordOffset;\n#else\nreturn -texCoordOffset;\n#endif\n}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentFunctions = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js deleted file mode 100644 index 918a4e2554e..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js +++ /dev/null @@ -1,72 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapFragmentMainFunctions"; -const shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) -#if defined(TANGENT) && defined(NORMAL) -varying mat3 vTBN; -#endif -#ifdef OBJECTSPACE_NORMALMAP -uniform mat4 normalMatrix; -#if defined(WEBGL2) || defined(WEBGPU) -mat4 toNormalMatrix(mat4 wMatrix) -{mat4 ret=inverse(wMatrix);ret=transpose(ret);ret[0][3]=0.;ret[1][3]=0.;ret[2][3]=0.;ret[3]=vec4(0.,0.,0.,1.);return ret;} -#else -mat4 toNormalMatrix(mat4 m) -{float -a00=m[0][0],a01=m[0][1],a02=m[0][2],a03=m[0][3], -a10=m[1][0],a11=m[1][1],a12=m[1][2],a13=m[1][3], -a20=m[2][0],a21=m[2][1],a22=m[2][2],a23=m[2][3], -a30=m[3][0],a31=m[3][1],a32=m[3][2],a33=m[3][3], -b00=a00*a11-a01*a10, -b01=a00*a12-a02*a10, -b02=a00*a13-a03*a10, -b03=a01*a12-a02*a11, -b04=a01*a13-a03*a11, -b05=a02*a13-a03*a12, -b06=a20*a31-a21*a30, -b07=a20*a32-a22*a30, -b08=a20*a33-a23*a30, -b09=a21*a32-a22*a31, -b10=a21*a33-a23*a31, -b11=a22*a33-a23*a32, -det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;mat4 mi=mat4( -a11*b11-a12*b10+a13*b09, -a02*b10-a01*b11-a03*b09, -a31*b05-a32*b04+a33*b03, -a22*b04-a21*b05-a23*b03, -a12*b08-a10*b11-a13*b07, -a00*b11-a02*b08+a03*b07, -a32*b02-a30*b05-a33*b01, -a20*b05-a22*b02+a23*b01, -a10*b10-a11*b08+a13*b06, -a01*b08-a00*b10-a03*b06, -a30*b04-a31*b02+a33*b00, -a21*b02-a20*b04-a23*b00, -a11*b07-a10*b09-a12*b06, -a00*b09-a01*b07+a02*b06, -a31*b01-a30*b03-a32*b00, -a20*b03-a21*b01+a22*b00)/det;return mat4(mi[0][0],mi[1][0],mi[2][0],mi[3][0], -mi[0][1],mi[1][1],mi[2][1],mi[3][1], -mi[0][2],mi[1][2],mi[2][2],mi[3][2], -mi[0][3],mi[1][3],mi[2][3],mi[3][3]);} -#endif -#endif -vec3 perturbNormalBase(mat3 cotangentFrame,vec3 normal,float scale) -{ -#ifdef NORMALXYSCALE -normal=normalize(normal*vec3(scale,scale,1.0)); -#endif -return normalize(cotangentFrame*normal);} -vec3 perturbNormal(mat3 cotangentFrame,vec3 textureSample,float scale) -{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);} -mat3 cotangent_frame(vec3 normal,vec3 p,vec2 uv,vec2 tangentSpaceParams) -{vec3 dp1=dFdx(p);vec3 dp2=dFdy(p);vec2 duv1=dFdx(uv);vec2 duv2=dFdy(uv);vec3 dp2perp=cross(dp2,normal);vec3 dp1perp=cross(normal,dp1);vec3 tangent=dp2perp*duv1.x+dp1perp*duv2.x;vec3 bitangent=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;float det=max(dot(tangent,tangent),dot(bitangent,bitangent));float invmax=det==0.0 ? 0.0 : inversesqrt(det);return mat3(tangent*invmax,bitangent*invmax,normal);} -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStore[name]) { - ShaderStore.IncludesShadersStore[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragmentMainFunctions = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragmentMainFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map deleted file mode 100644 index 3d2d817225e..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragmentMainFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentMainFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,uCAAuC,CAAC;AACrD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6Dd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragmentMainFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL)\n#if defined(TANGENT) && defined(NORMAL) \nvarying mat3 vTBN;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\nuniform mat4 normalMatrix;\n#if defined(WEBGL2) || defined(WEBGPU)\nmat4 toNormalMatrix(mat4 wMatrix)\n{mat4 ret=inverse(wMatrix);ret=transpose(ret);ret[0][3]=0.;ret[1][3]=0.;ret[2][3]=0.;ret[3]=vec4(0.,0.,0.,1.);return ret;}\n#else\nmat4 toNormalMatrix(mat4 m)\n{float\na00=m[0][0],a01=m[0][1],a02=m[0][2],a03=m[0][3],\na10=m[1][0],a11=m[1][1],a12=m[1][2],a13=m[1][3],\na20=m[2][0],a21=m[2][1],a22=m[2][2],a23=m[2][3],\na30=m[3][0],a31=m[3][1],a32=m[3][2],a33=m[3][3],\nb00=a00*a11-a01*a10,\nb01=a00*a12-a02*a10,\nb02=a00*a13-a03*a10,\nb03=a01*a12-a02*a11,\nb04=a01*a13-a03*a11,\nb05=a02*a13-a03*a12,\nb06=a20*a31-a21*a30,\nb07=a20*a32-a22*a30,\nb08=a20*a33-a23*a30,\nb09=a21*a32-a22*a31,\nb10=a21*a33-a23*a31,\nb11=a22*a33-a23*a32,\ndet=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;mat4 mi=mat4(\na11*b11-a12*b10+a13*b09,\na02*b10-a01*b11-a03*b09,\na31*b05-a32*b04+a33*b03,\na22*b04-a21*b05-a23*b03,\na12*b08-a10*b11-a13*b07,\na00*b11-a02*b08+a03*b07,\na32*b02-a30*b05-a33*b01,\na20*b05-a22*b02+a23*b01,\na10*b10-a11*b08+a13*b06,\na01*b08-a00*b10-a03*b06,\na30*b04-a31*b02+a33*b00,\na21*b02-a20*b04-a23*b00,\na11*b07-a10*b09-a12*b06,\na00*b09-a01*b07+a02*b06,\na31*b01-a30*b03-a32*b00,\na20*b03-a21*b01+a22*b00)/det;return mat4(mi[0][0],mi[1][0],mi[2][0],mi[3][0],\nmi[0][1],mi[1][1],mi[2][1],mi[3][1],\nmi[0][2],mi[1][2],mi[2][2],mi[3][2],\nmi[0][3],mi[1][3],mi[2][3],mi[3][3]);}\n#endif\n#endif\nvec3 perturbNormalBase(mat3 cotangentFrame,vec3 normal,float scale)\n{\n#ifdef NORMALXYSCALE\nnormal=normalize(normal*vec3(scale,scale,1.0));\n#endif\nreturn normalize(cotangentFrame*normal);}\nvec3 perturbNormal(mat3 cotangentFrame,vec3 textureSample,float scale)\n{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);}\nmat3 cotangent_frame(vec3 normal,vec3 p,vec2 uv,vec2 tangentSpaceParams)\n{vec3 dp1=dFdx(p);vec3 dp2=dFdy(p);vec2 duv1=dFdx(uv);vec2 duv2=dFdy(uv);vec3 dp2perp=cross(dp2,normal);vec3 dp1perp=cross(normal,dp1);vec3 tangent=dp2perp*duv1.x+dp1perp*duv2.x;vec3 bitangent=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;float det=max(dot(tangent,tangent),dot(bitangent,bitangent));float invmax=det==0.0 ? 0.0 : inversesqrt(det);return mat3(tangent*invmax,bitangent*invmax,normal);}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentMainFunctions = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js deleted file mode 100644 index fc749f98a86..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js +++ /dev/null @@ -1,16 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapVertex"; -const shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) -#if defined(TANGENT) && defined(NORMAL) -vec3 tbnNormal=normalize(normalUpdated);vec3 tbnTangent=normalize(tangentUpdated.xyz);vec3 tbnBitangent=cross(tbnNormal,tbnTangent)*tangentUpdated.w;vTBN=mat3(finalWorld)*mat3(tbnTangent,tbnBitangent,tbnNormal); -#endif -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStore[name]) { - ShaderStore.IncludesShadersStore[name] = shader; -} -/** @internal */ -export const openpbrNormalMapVertex = { name, shader }; -//# sourceMappingURL=openpbrNormalMapVertex.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map deleted file mode 100644 index b3b110c800a..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertex.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapVertex.js","sourceRoot":"","sources":["openpbrNormalMapVertex.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,wBAAwB,CAAC;AACtC,MAAM,MAAM,GAAG;;;;;CAKd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapVertex\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nvec3 tbnNormal=normalize(normalUpdated);vec3 tbnTangent=normalize(tangentUpdated.xyz);vec3 tbnBitangent=cross(tbnNormal,tbnTangent)*tangentUpdated.w;vTBN=mat3(finalWorld)*mat3(tbnTangent,tbnBitangent,tbnNormal);\n#endif\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapVertex = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js deleted file mode 100644 index 9d691d6b7e3..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js +++ /dev/null @@ -1,16 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapVertexDeclaration"; -const shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) -#if defined(TANGENT) && defined(NORMAL) -varying mat3 vTBN; -#endif -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStore[name]) { - ShaderStore.IncludesShadersStore[name] = shader; -} -/** @internal */ -export const openpbrNormalMapVertexDeclaration = { name, shader }; -//# sourceMappingURL=openpbrNormalMapVertexDeclaration.js.map \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map deleted file mode 100644 index d48345c1b0f..00000000000 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapVertexDeclaration.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapVertexDeclaration.js","sourceRoot":"","sources":["openpbrNormalMapVertexDeclaration.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;CAKd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1C,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACpD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapVertexDeclaration\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL) \nvarying mat3 vTBN;\n#endif\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStore[name]) {\n ShaderStore.IncludesShadersStore[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapVertexDeclaration = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index f5be25469e3..b0d9ce09031 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -63,30 +63,14 @@ precision highp float; #include #include -#include -#include +// #include #include #include -struct openpbrLightingInfo -{ - vec3 material_final; - // vec3 specular; - // float fresnel; - // vec3 slab_diffuse = vec3(0., 0., 0.); - // vec3 slab_subsurface = vec3(0., 0., 0.); - // vec3 slab_translucent = vec3(0., 0., 0.); - // vec3 slab_glossy = vec3(0., 0., 0.); - // float specularFresnel = 0.0; - // vec3 slab_metal = vec3(0., 0., 0.); - // vec3 slab_coat = vec3(0., 0., 0.); - // float coatFresnel = 0.0; - // vec3 slab_fuzz = vec3(0., 0., 0.); -}; - -vec3 layer(vec3 slab_bottom, vec3 slab_top, float fresnel, vec3 bottom_multiplier, vec3 top_multiplier) { - - return mix(slab_bottom * bottom_multiplier, slab_top * top_multiplier, fresnel); +// Do a mix between layers with additional multipliers for each layer. +vec3 layer(vec3 slab_bottom, vec3 slab_top, float lerp_factor, vec3 bottom_multiplier, vec3 top_multiplier) { + + return mix(slab_bottom * bottom_multiplier, slab_top * top_multiplier, lerp_factor); } // _____________________________ MAIN FUNCTION ____________________________ @@ -147,80 +131,6 @@ void main(void) { normalW, viewDirectionW.xyz, specular_roughness, geometricNormalW ); - // _____________________________ Base Diffuse Layer IBL _______________________________________ - #ifdef REFLECTION - // Pass in a vector to sample teh irradiance with (to handle reflection or ) - vec3 baseDiffuseEnvironmentLight = sampleIrradiance( - normalW - #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 - #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo - #ifdef IBL_CDF_FILTERING - , icdfSampler - #endif - #endif - , vReflectionInfos - , viewDirectionW - , base_diffuse_roughness - , base_color - ); - - // _____________________________ Base Specular Layer IBL _______________________________________ - - #ifdef REFLECTIONMAP_3D - vec3 reflectionCoords = vec3(0., 0., 0.); - #else - vec2 reflectionCoords = vec2(0., 0.); - #endif - reflectionCoords = createReflectionCoords(vPositionW, normalW); - float specularAlphaG = specular_roughness * specular_roughness; - vec3 baseSpecularEnvironmentLight = sampleRadiance(specularAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos - #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) - , baseGeoInfo.NdotVUnclamped - #endif - , reflectionSampler - , reflectionCoords - #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo - #endif - ); - - baseSpecularEnvironmentLight = mix(baseSpecularEnvironmentLight.rgb, baseDiffuseEnvironmentLight, specularAlphaG); - - vec3 coatEnvironmentLight = vec3(0., 0., 0.); - if (coat_weight > 0.0) { - #ifdef REFLECTIONMAP_3D - vec3 reflectionCoords = vec3(0., 0., 0.); - #else - vec2 reflectionCoords = vec2(0., 0.); - #endif - reflectionCoords = createReflectionCoords(vPositionW, coatNormalW); - float coatAlphaG = coat_roughness * coat_roughness; - coatEnvironmentLight = sampleRadiance(coatAlphaG, vReflectionMicrosurfaceInfos.rgb, vReflectionInfos - #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) - , coatGeoInfo.NdotVUnclamped - #endif - , reflectionSampler - , reflectionCoords - #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo - #endif - ); - } - - #endif - // _______________________ F0 and F90 Reflectance _______________________________ // Coat @@ -248,76 +158,11 @@ void main(void) { ReflectanceParams baseConductorReflectance; baseConductorReflectance = conductorReflectance(base_color, specular_color, specular_weight); - // ______________________________ IBL Fresnel Reflectance ____________________________ - #ifdef REFLECTION - - // Dielectric IBL Fresnel - // The colored fresnel represents the % of light reflected by the base specular lobe - // The non-colored fresnel represents the % of light that doesn't penetrate through - // the base specular lobe. i.e. the specular lobe isn't energy conserving for coloured specular. - float dielectricIblFresnel = getReflectanceFromBRDFLookup(vec3(baseDielectricReflectance.F0), vec3(baseDielectricReflectance.F90), baseGeoInfo.environmentBrdf).r; - vec3 dielectricIblColoredFresnel = getReflectanceFromBRDFLookup(baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, baseGeoInfo.environmentBrdf); - - // Conductor IBL Fresnel - vec3 conductorIblFresnel = conductorIblFresnel(baseConductorReflectance, baseGeoInfo.NdotV, specular_roughness, baseGeoInfo.environmentBrdf); - - // Coat IBL Fresnel - float coatIblFresnel = 0.0; - if (coat_weight > 0.0) { - coatIblFresnel = getReflectanceFromBRDFLookup(vec3(coatReflectance.F0), vec3(coatReflectance.F90), coatGeoInfo.environmentBrdf).r; - // Prevent the light reflected by the coat from being added to the base layer - // dielectricIblFresnel -= coatIblFresnel; - // dielectricIblColoredFresnel = max(dielectricIblColoredFresnel - vec3(coatIblFresnel), 0.0); - // conductorIblFresnel = max(conductorIblFresnel - vec3(coatIblFresnel), 0.0); - } - #endif - + // ________________________ Environment (IBL) Lighting ____________________________ vec3 material_surface_ibl = vec3(0., 0., 0.); - vec3 slab_diffuse_ibl = vec3(0., 0., 0.); - vec3 slab_glossy_ibl = vec3(0., 0., 0.); - vec3 slab_metal_ibl = vec3(0., 0., 0.); - vec3 slab_coat_ibl = vec3(0., 0., 0.); - #ifdef REFLECTION - slab_diffuse_ibl = baseDiffuseEnvironmentLight * vLightingIntensity.z; - slab_diffuse_ibl *= aoOut.ambientOcclusionColor; - - // Add the specular environment light - slab_glossy_ibl = baseSpecularEnvironmentLight * vLightingIntensity.z; - - // _____________________________ Metal Layer IBL ____________________________ - slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; - - // _____________________________ Coat Layer IBL _____________________________ - if (coat_weight > 0.0) { - slab_coat_ibl = coatEnvironmentLight * vLightingIntensity.z; - } - - // TEMP - vec3 slab_subsurface_ibl = vec3(0., 0., 0.); - vec3 slab_translucent_base_ibl = vec3(0., 0., 0.); - vec3 slab_fuzz_ibl = vec3(0., 0., 0.); - - slab_diffuse_ibl *= base_color.rgb; - - // _____________________________ IBL Material Layer Composition ______________________________________ - #define CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION - vec3 material_opaque_base_ibl = mix(slab_diffuse_ibl, slab_subsurface_ibl, subsurface_weight); - vec3 material_dielectric_base_ibl = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); - vec3 material_dielectric_gloss_ibl = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3(1.0), specular_color); - vec3 material_base_substrate_ibl = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); - vec3 material_coated_base_ibl = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3(1.0)); - material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); - - #endif - - - // __________________________ Direct Lighting Info ____________________________ - vec3 baseDiffuseDirectLight = vec3(0., 0., 0.); - #ifdef SPECULARTERM - vec3 baseSpecularDirectLight = vec3(0., 0., 0.); - #endif + #include - // Direct Lighting Variables + // __________________________ Direct Lighting ____________________________ vec3 material_surface_direct = vec3(0., 0., 0.); #if defined(LIGHT0) float aggShadow = 0.; @@ -327,27 +172,25 @@ void main(void) { #endif - // _____________________________ Emission ________________________________________ - vec3 finalEmission = vEmissionColor; + // _________________________ Emissive Lighting _______________________________ + vec3 material_surface_emission = vEmissionColor; #ifdef EMISSION_COLOR vec3 emissionColorTex = texture2D(emissionColorSampler, vEmissionColorUV + uvOffset).rgb; #ifdef EMISSION_COLOR_GAMMA - finalEmission *= toLinearSpace(emissionColorTex.rgb); + material_surface_emission *= toLinearSpace(emissionColorTex.rgb); #else - finalEmission *= emissionColorTex.rgb; + material_surface_emission *= emissionColorTex.rgb; #endif - finalEmission *= vEmissionColorInfos.y; + material_surface_emission *= vEmissionColorInfos.y; #endif - finalEmission *= vLightingIntensity.y; + material_surface_emission *= vLightingIntensity.y; // _____________________________ Final Color Composition ________________________ #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - vec4 finalColor = vec4(material_surface_ibl + material_surface_direct, alpha); + vec4 finalColor = vec4(material_surface_ibl + material_surface_direct + material_surface_emission, alpha); - // _____________________________ EmissiveLight _____________________________________ - finalColor.rgb += finalEmission; #define CUSTOM_FRAGMENT_BEFORE_FOG diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx index 5966717b64d..f06b091c6aa 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx @@ -36,7 +36,7 @@ uniform vSphericalXY: vec3f; uniform vSphericalYZ: vec3f; uniform vSphericalZX: vec3f; -uniform baseWeight: f32; +uniform vBaseWeight: f32; uniform vBaseColor: vec4f; uniform vBaseDiffuseRoughness: f32; uniform vReflectanceInfo: vec4f; diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx new file mode 100644 index 00000000000..2354074a462 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx @@ -0,0 +1,138 @@ +// This code reads uniforms and samples textures to fill up the base and specular +// layer properties for OpenPBR + +// Base Layer Properties +// We don't include base_weight in our initial variables because it is multiplied +// into the base_color in this code snippet. +var base_color = vec3f(0.8); +var base_metalness: f32 = 0.0; +var base_diffuse_roughness: f32 = 0.0; + +// Specular Layer Properties +var specular_weight: f32 = 1.0; +var specular_roughness: f32 = 0.3; +var specular_color: vec3f = vec3f(1.0); +var specular_roughness_anisotropy: f32 = 0.0; +var specular_ior: f32 = 1.5; +var alpha: f32 = 1.0; + +// Sample Base Layer properties from textures +#ifdef BASE_WEIGHT + var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, uniforms.vBaseWeightUV + uvOffset); +#endif + +#ifdef BASE_COLOR + var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, uniforms.vBaseColorUV + uvOffset); +#endif + +#ifdef METALLIC_ROUGHNESS + var metallicRoughnessFromTexture: vec4f = textureSample(baseMetalRoughSampler, baseMetalRoughSamplerSampler, uniforms.vBaseMetalRoughUV + uvOffset); +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + var baseDiffuseRoughnessFromTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, uniforms.vBaseDiffuseRoughnessUV + uvOffset).r; +#endif + +#ifdef GEOMETRY_OPACITY + var opacityFromTexture: vec4f = textureSample(opacitySampler, opacitySamplerSampler, uniforms.vOpacityUV + uvOffset); +#endif + +#ifdef DECAL + var decalFromTexture: vec4f = textureSample(decalSampler, decalSamplerSampler, uniforms.vDecalUV + uvOffset); +#endif + +#ifdef SPECULAR_COLOR + var specularColorFromTexture: vec4f = textureSample(specularColorSampler, specularColorSamplerSampler, uniforms.vSpecularColorUV + uvOffset); + #ifdef SPECULAR_COLOR_GAMMA + specularColorFromTexture = toLinearSpace(specularColorFromTexture.rgb); + #endif +#endif + +#ifdef SPECULAR_WEIGHT + var specularWeightFromTexture: vec4f = textureSample(specularWeightSampler, specularWeightSamplerSampler, uniforms.vSpecularWeightUV + uvOffset); +#endif + +// Initalize base layer properties from uniforms +base_color = uniforms.vBaseColor.rgb; +#if defined(VERTEXCOLOR) || defined(INSTANCESCOLOR) && defined(INSTANCES) + base_color *= uniforms.vColor.rgb; +#endif +#if defined(VERTEXALPHA) || defined(INSTANCESCOLOR) && defined(INSTANCES) + alpha *= uniforms.vColor.a; +#endif +base_color *= vec3(uniforms.vBaseWeight); +alpha = uniforms.vBaseColor.a; +base_metalness = uniforms.vReflectanceInfo.x; +base_diffuse_roughness = uniforms.vBaseDiffuseRoughness; +specular_roughness = uniforms.vReflectanceInfo.y; +specular_color = uniforms.vSpecularColor.rgb; +specular_weight = uniforms.vReflectanceInfo.a; +specular_ior = uniforms.vReflectanceInfo.z; + +// Apply texture values to base layer properties + +#ifdef BASE_COLOR + #if defined(ALPHAFROMALBEDO) || defined(ALPHATEST) + alpha *= baseColorFromTexture.a; + #endif + + #ifdef BASE_COLOR_GAMMA + base_color *= toLinearSpace(baseColorFromTexture.rgb); + #else + base_color *= baseColorFromTexture.rgb; + #endif + + base_color *= uniforms.vBaseColorInfos.y; +#endif + +#ifdef BASE_WEIGHT + base_color *= baseWeightFromTexture.r; +#endif + +// _____________________________ Alpha Information _______________________________ +#ifdef GEOMETRY_OPACITY + alpha *= opacityFromTexture.a; + alpha *= uniforms.vGeometryOpacityInfos.y; +#endif + +#ifdef ALPHATEST + #if DEBUGMODE != 88 + if (alpha < ALPHATESTVALUE) + discard; + #endif + + #ifndef ALPHABLEND + // Prevent to blend with the canvas. + alpha = 1.0; + #endif +#endif + +#ifdef METALLIC_ROUGHNESS + base_metalness *= metallicRoughnessFromTexture.b; + specular_roughness *= metallicRoughnessFromTexture.g; +#endif + +#ifdef BASE_DIFFUSE_ROUGHNESS + base_diffuse_roughness *= baseDiffuseRoughnessFromTexture * uniforms.vBaseDiffuseRoughnessInfos.y; +#endif + +#ifdef SPECULAR_COLOR + specular_color *= specularColorFromTexture.rgb; +#endif + +#ifdef SPECULAR_WEIGHT + // 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 + specular_weight *= specularWeightFromTexture.a; + #else + specular_weight *= specularWeightFromTexture.r; + #endif +#endif + +#ifdef DETAIL + let detailRoughness: f32 = mix(0.5f, detailColor.b, vDetailInfos.w); + let loLerp: f32 = mix(0.f, specular_roughness, detailRoughness * 2.f); + let hiLerp: f32 = mix(specular_roughness, 1.f, (detailRoughness - 0.5f) * 2.f); + specular_roughness = mix(loLerp, hiLerp, step(detailRoughness, 0.5f)); +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx deleted file mode 100644 index beeab50f8ec..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAlbedoOpacity.fx +++ /dev/null @@ -1,116 +0,0 @@ -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/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx deleted file mode 100644 index 4e3cb25c47f..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx +++ /dev/null @@ -1,31 +0,0 @@ -struct ambientOcclusionOutParams -{ - ambientOcclusionColor: vec3f, -#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) - ambientOcclusionColorMap: vec3f -#endif -}; - -#define pbr_inline -fn ambientOcclusionBlock( -#ifdef AMBIENT_OCCLUSION - ambientOcclusionFromTexture: vec3f, - ambientOcclusionInfos: vec2f -#endif -) -> ambientOcclusionOutParams -{ - var outParams: ambientOcclusionOutParams; - var ambientOcclusionColor: vec3f = vec3f(1., 1., 1.); - - #ifdef AMBIENT_OCCLUSION - ambientOcclusionColor = vec3f(ambientOcclusionFromTexture.r * ambientOcclusionInfos.y); - - #if DEBUGMODE > 0 - outParams.ambientOcclusionColorMap = ambientOcclusionFromTexture; - #endif - #endif - - outParams.ambientOcclusionColor = ambientOcclusionColor; - - return outParams; -} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx deleted file mode 100644 index ee6e9c4b435..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockFinalLitComponents.fx +++ /dev/null @@ -1,54 +0,0 @@ -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 \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx deleted file mode 100644 index dd0564f851e..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockGeometryInfo.fx +++ /dev/null @@ -1,35 +0,0 @@ -var NdotVUnclamped: f32 = dot(normalW, viewDirectionW); -// The order 1886 page 3. -var NdotV: f32 = absEps(NdotVUnclamped); -var alphaG: f32 = convertRoughnessToAverageSlope(roughness); -var AARoughnessFactors: vec2f = getAARoughnessFactors(normalW.xyz); - -#ifdef SPECULARAA - // Adapt linear roughness (alphaG) to geometric curvature of the current pixel. - alphaG += AARoughnessFactors.y; -#endif - -#if defined(ENVIRONMENTBRDF) - // BRDF Lookup - var environmentBrdf: vec3f = getBRDFLookup(NdotV, roughness); -#endif - -#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) - #ifdef RADIANCEOCCLUSION - #ifdef AMBIENTINGRAYSCALE - var ambientMonochrome: f32 = aoOut.ambientOcclusionColor.r; - #else - var ambientMonochrome: f32 = getLuminance(aoOut.ambientOcclusionColor); - #endif - - var seo: f32 = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped); - #endif - - #ifdef HORIZONOCCLUSION - #ifdef GEOMETRY_NORMAL - #ifdef REFLECTIONMAP_3D - var eho: f32 = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); - #endif - #endif - #endif -#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockNormalFinal.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockNormalFinal.fx new file mode 100644 index 00000000000..534ee45d5f4 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockNormalFinal.fx @@ -0,0 +1,19 @@ +#if defined(FORCENORMALFORWARD) && defined(NORMAL) + var faceNormal: vec3f = normalize(cross(dpdx(fragmentInputs.vPositionW), dpdy(fragmentInputs.vPositionW))) * scene.vEyePosition.w; + #if defined(TWOSIDEDLIGHTING) + faceNormal = select(-faceNormal, faceNormal, fragmentInputs.frontFacing); + #endif + + normalW *= sign(dot(normalW, faceNormal)); + coatNormalW *= sign(dot(coatNormalW, faceNormal)); +#endif + +#if defined(TWOSIDEDLIGHTING) && defined(NORMAL) + #if defined(MIRRORED) + normalW = select(normalW, -normalW, fragmentInputs.frontFacing); + coatNormalW = select(coatNormalW, -coatNormalW, fragmentInputs.frontFacing); + #else + normalW = select(-normalW, normalW, fragmentInputs.frontFacing); + coatNormalW = select(-coatNormalW, coatNormalW, fragmentInputs.frontFacing); + #endif +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx deleted file mode 100644 index 44d5e5c6e63..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectance.fx +++ /dev/null @@ -1,36 +0,0 @@ -#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 GEOMETRY_NORMAL - #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 deleted file mode 100644 index d36f6a3935a..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockReflectivity.fx +++ /dev/null @@ -1,137 +0,0 @@ -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/openpbrCoatLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx new file mode 100644 index 00000000000..c76ea84100f --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx @@ -0,0 +1,65 @@ +// This code reads uniforms and samples textures to fill up the coat +// layer properties for OpenPBR + +var coat_weight: f32 = 0.0f; +var coat_color: vec3f = vec3f(1.0f); +var coat_roughness: f32 = 0.0f; +var coat_roughness_anisotropy: f32 = 0.0f; +var coat_ior: f32 = 1.6f; +var coat_darkening: f32 = 1.0f; + +// Sample Coat Layer properties from textures +#ifdef COAT_WEIGHT + var coatWeightFromTexture: vec4f = textureSample(coatWeightSampler, coatWeightSamplerSampler, uniforms.vCoatWeightUV + uvOffset); +#endif + +#ifdef COAT_COLOR + var coatColorFromTexture: vec4f = textureSample(coatColorSampler, coatColorSamplerSampler, uniforms.vCoatColorUV + uvOffset); +#endif + +#ifdef COAT_ROUGHNESS + var coatRoughnessFromTexture: vec4f = textureSample(coatRoughnessSampler, coatRoughnessSamplerSampler, uniforms.vCoatRoughnessUV + uvOffset); +#endif + +#ifdef COAT_ROUGHNESS_ANISOTROPY + var coatRoughnessAnisotropyFromTexture: f32 = textureSample(coatRoughnessAnisotropySampler, coatRoughnessAnisotropySamplerSampler, uniforms.vCoatRoughnessAnisotropyUV + uvOffset).r; +#endif + +#ifdef COAT_DARKENING + var coatDarkeningFromTexture: vec4f = textureSample(coatDarkeningSampler, coatDarkeningSamplerSampler, uniforms.vCoatDarkeningUV + uvOffset); +#endif + +// Initalize coat layer properties from uniforms +coat_color = uniforms.vCoatColor.rgb; +coat_weight = uniforms.vCoatWeight; +coat_roughness = uniforms.vCoatRoughness; +// coat_roughness_anisotropy = uniforms.vCoatRoughnessAnisotropy; +coat_ior = uniforms.vCoatIor; +// coat_darkening = uniforms.vCoatDarkening; + +// Apply texture values to coat layer properties +#ifdef COAT_WEIGHT + coat_weight *= coatWeightFromTexture.r; +#endif + +#ifdef COAT_COLOR + #ifdef COAT_COLOR_GAMMA + coat_color *= toLinearSpace(coatColorFromTexture.rgb); + #else + coat_color *= coatColorFromTexture.rgb; + #endif + + coat_color *= uniforms.vCoatColorInfos.y; +#endif + +#ifdef COAT_ROUGHNESS + coat_roughness *= coatRoughnessFromTexture.r; +#endif + +#ifdef COAT_ROUGHNESS_ANISOTROPY + coat_roughness_anisotropy *= coatRoughnessAnisotropyFromTexture; +#endif + +#ifdef COAT_DARKENING + coat_darkening *= coatDarkeningFromTexture.r; +#endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrConductorReflectance.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrConductorReflectance.fx new file mode 100644 index 00000000000..2bedc060fb5 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrConductorReflectance.fx @@ -0,0 +1,17 @@ + +#define pbr_inline +fn conductorReflectance(baseColor: vec3f, specularColor: vec3f, specularWeight: f32) -> ReflectanceParams +{ + var outParams: ReflectanceParams; + + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + outParams.coloredF0 = baseColor * specularWeight; + outParams.coloredF90 = specularColor * specularWeight; + #else + outParams.coloredF0 = baseColor; + outParams.coloredF90 = vec3f(1.0f); + #endif + outParams.F0 = 1.0f; + outParams.F90 = 1.0f; + return outParams; +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.fx new file mode 100644 index 00000000000..55812b8895d --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.fx @@ -0,0 +1,53 @@ +struct ReflectanceParams +{ + F0: f32, + F90: f32, + coloredF0: vec3f, + coloredF90: vec3f, +}; + +#define pbr_inline +fn dielectricReflectance( + insideIOR: f32, outsideIOR: f32, specularColor: vec3f, specularWeight: f32 +) -> ReflectanceParams +{ + var outParams: ReflectanceParams; + + let dielectricF0 = pow((insideIOR - outsideIOR) / (insideIOR + outsideIOR), 2.0); + + // 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 = max(specularColor.r, max(specularColor.g, specularColor.b)); + outParams.F0 = dielectricF0 * maxF0 * specularWeight; + #else + outParams.F0 = dielectricF0 * specularWeight; + #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. + let f90Scale = clamp(2.0f * abs(insideIOR - outsideIOR), 0.0f, 1.0f); + outParams.F90 = f90Scale * specularWeight; + + // 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 layer below. The non-coloured F0 will be used for this (see below). + outParams.coloredF0 = vec3f(dielectricF0 * specularWeight) * specularColor.rgb; + + // 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(f90Scale) * specularWeight; + #else + // In glTF, the F90 is white for dielectrics. + let dielectricColorF90: vec3f = vec3f(f90Scale) * specularWeight; + #endif + outParams.coloredF90 = dielectricColorF90; + + return outParams; +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx new file mode 100644 index 00000000000..ccbfaadc7ef --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx @@ -0,0 +1,93 @@ +#ifdef LIGHT{X} +{ + var slab_diffuse: vec3f = vec3f(0.f, 0.f, 0.f); + var slab_subsurface: vec3f = vec3f(0.f, 0.f, 0.f); + var slab_translucent: vec3f = vec3f(0.f, 0.f, 0.f); + var slab_glossy: vec3f = vec3f(0.f, 0.f, 0.f); + var specularFresnel: f32 = 0.0f; + var slab_metal: vec3f = vec3f(0.f, 0.f, 0.f); + var slab_coat: vec3f = vec3f(0.f, 0.f, 0.f); + var coatFresnel: f32 = 0.0f; + var slab_fuzz: vec3f = vec3f(0.f, 0.f, 0.f); + + // Diffuse Lobe + #ifdef HEMILIGHT{X} + slab_diffuse = computeHemisphericDiffuseLighting(preInfo{X}, lightColor{X}.rgb, light{X}.vLightGround); + #elif defined(AREALIGHT{X}) + slab_diffuse = computeAreaDiffuseLighting(preInfo{X}, lightColor{X}.rgb); + #else + slab_diffuse = computeDiffuseLighting(preInfo{X}, lightColor{X}.rgb); + #endif + + #ifdef PROJECTEDLIGHTTEXTURE{X} + slab_diffuse *= computeProjectionTextureDiffuseLighting(projectionLightTexture{X}, textureProjectionMatrix{X}, vPositionW); + #endif + + numLights += 1.0f; + + // Specular Lobe + #if AREALIGHT{X} + slab_glossy = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, baseConductorReflectance.F0, baseConductorReflectance.F90); + #else + { + #ifdef ANISOTROPIC + slab_glossy = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, + anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, + vec3f(baseDielectricReflectance.F0), vec3f(baseDielectricReflectance.F90), baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_glossy = computeSpecularLighting(preInfo{X}, normalW, baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, specular_roughness, lightColor{X}.rgb); + #endif + + let NdotH: f32 = dot(normalW, preInfo{X}.H); + specularFresnel = fresnelSchlickGGX(NdotH, baseDielectricReflectance.F0, baseDielectricReflectance.F90); + } + #endif + + // Metal Lobe + #if AREALIGHT{X} + slab_metal = computeAreaSpecularLighting(preInfo{X}, light{X}.vLightSpecular.rgb, baseConductorReflectance.F0, baseConductorReflectance.F90); + #else + { + // For OpenPBR, we use the F82 specular model for metallic materials and mix with the + // usual Schlick lobe. + #if (CONDUCTOR_SPECULAR_MODEL == CONDUCTOR_SPECULAR_MODEL_OPENPBR) + let coloredFresnel: vec3f = specular_weight * getF82Specular(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90, specular_roughness); + #else + let coloredFresnel: vec3f = fresnelSchlickGGX(preInfo{X}.VdotH, baseConductorReflectance.coloredF0, baseConductorReflectance.coloredF90); + #endif + + #ifdef ANISOTROPIC + slab_metal = computeAnisotropicSpecularLighting(preInfo{X}, viewDirectionW, normalW, anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, specularEnvironmentR0, specularEnvironmentR90, baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_metal = computeSpecularLighting(preInfo{X}, normalW, vec3f(baseConductorReflectance.coloredF0), coloredFresnel, specular_roughness, lightColor{X}.rgb); + #endif + } + #endif + + // Coat Lobe + #if AREALIGHT{X} + slab_coat = computeAreaSpecularLighting(preInfoCoat{X}, light{X}.vLightSpecular.rgb, coatReflectance.F0, coatReflectance.F90); + #else + { + #ifdef ANISOTROPIC + slab_coat = computeAnisotropicSpecularLighting(preInfoCoat{X}, viewDirectionW, coatNormalW, + anisotropicOut.anisotropicTangent, anisotropicOut.anisotropicBitangent, anisotropicOut.anisotropy, + vec3f(coatReflectance.F0), vec3f(coatReflectance.F90), baseGeoInfo.AARoughnessFactors.x, lightColor{X}.rgb); + #else + slab_coat = computeSpecularLighting(preInfoCoat{X}, coatNormalW, vec3f(coatReflectance.F0), vec3f(1.0f), coat_roughness, lightColor{X}.rgb); + #endif + + let NdotH: f32 = dot(coatNormalW, preInfoCoat{X}.H); + coatFresnel = fresnelSchlickGGX(NdotH, coatReflectance.F0, coatReflectance.F90); + } + #endif + + slab_diffuse *= base_color.rgb; + let material_opaque_base: vec3f = mix(slab_diffuse, slab_subsurface, subsurface_weight); + let material_dielectric_base: vec3f = mix(material_opaque_base, slab_translucent, transmission_weight); + let material_dielectric_gloss: vec3f = layer(material_dielectric_base, slab_glossy, specularFresnel, vec3f(1.0), specular_color); + let material_base_substrate: vec3f = mix(material_dielectric_gloss, slab_metal, base_metalness); + let material_coated_base: vec3f = layer(material_base_substrate, slab_coat, coatFresnel, coat_color, vec3f(1.0)); + material_surface_direct += mix(material_coated_base, slab_fuzz, fuzz_weight); +} +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.fx new file mode 100644 index 00000000000..529ed5b74ac --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.fx @@ -0,0 +1,93 @@ +#ifdef LIGHT{X} + var preInfo{X}: preLightingInfo; + var preInfoCoat{X}: preLightingInfo; + + let lightColor{X}: vec4f = light{X}.vLightDiffuse; + var shadow{X}: f32 = 1.0f; + #if defined(SHADOWONLY) || defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}) + //No light calculation + #else + + #define CUSTOM_LIGHT{X}_COLOR // Use to modify light color. Currently only supports diffuse. + + // Compute Pre Lighting infos + #ifdef SPOTLIGHT{X} + preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + preInfoCoat{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW, vPositionW); + #elif defined(POINTLIGHT{X}) + preInfo{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW, vPositionW); + preInfoCoat{X} = computePointAndSpotPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW, vPositionW); + #elif defined(HEMILIGHT{X}) + preInfo{X} = computeHemisphericPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + preInfoCoat{X} = computeHemisphericPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW); + #elif defined(DIRLIGHT{X}) + preInfo{X} = computeDirectionalPreLightingInfo(light{X}.vLightData, viewDirectionW, normalW); + preInfoCoat{X} = computeDirectionalPreLightingInfo(light{X}.vLightData, viewDirectionW, coatNormalW); + #elif defined(AREALIGHT{X}) && defined(AREALIGHTSUPPORTED) + preInfo{X} = computeAreaPreLightingInfo(areaLightsLTC1Sampler, areaLightsLTC2Sampler, viewDirectionW, normalW, vPositionW, light{X}.vLightData, light{X}.vLightWidth.xyz, light{X}.vLightHeight.xyz, specular_roughness); + preInfoCoat{X} = computeAreaPreLightingInfo(areaLightsLTC1Sampler, areaLightsLTC2Sampler, viewDirectionW, coatNormalW, vPositionW, light{X}.vLightData, light{X}.vLightWidth.xyz, light{X}.vLightHeight.xyz, coat_roughness); + #endif + + preInfo{X}.NdotV = baseGeoInfo.NdotV; + preInfoCoat{X}.NdotV = coatGeoInfo.NdotV; + + // Compute Attenuation infos + #ifdef SPOTLIGHT{X} + #ifdef LIGHT_FALLOFF_GLTF{X} + preInfo{X}.attenuation = computeDistanceLightFalloff_GLTF(preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.y); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_GLTF(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightFalloff.z, light{X}.vLightFalloff.w); + #endif + #elif defined(LIGHT_FALLOFF_PHYSICAL{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Physical(preInfo{X}.lightDistanceSquared); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_Physical(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w); + #endif + #elif defined(LIGHT_FALLOFF_STANDARD{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Standard(preInfo{X}.lightOffset, light{X}.vLightFalloff.x); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff_Standard(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w, light{X}.vLightData.w); + #endif + #else + preInfo{X}.attenuation = computeDistanceLightFalloff(preInfo{X}.lightOffset, preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.x, light{X}.vLightFalloff.y); + #ifdef IESLIGHTTEXTURE{X} + preInfo{X}.attenuation *= computeDirectionalLightFalloff_IES(light{X}.vLightDirection.xyz, preInfo{X}.L, iesLightTexture{X}); + #else + preInfo{X}.attenuation *= computeDirectionalLightFalloff(light{X}.vLightDirection.xyz, preInfo{X}.L, light{X}.vLightDirection.w, light{X}.vLightData.w, light{X}.vLightFalloff.z, light{X}.vLightFalloff.w); + #endif + #endif + #elif defined(POINTLIGHT{X}) + #ifdef LIGHT_FALLOFF_GLTF{X} + preInfo{X}.attenuation = computeDistanceLightFalloff_GLTF(preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.y); + #elif defined(LIGHT_FALLOFF_PHYSICAL{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Physical(preInfo{X}.lightDistanceSquared); + #elif defined(LIGHT_FALLOFF_STANDARD{X}) + preInfo{X}.attenuation = computeDistanceLightFalloff_Standard(preInfo{X}.lightOffset, light{X}.vLightFalloff.x); + #else + preInfo{X}.attenuation = computeDistanceLightFalloff(preInfo{X}.lightOffset, preInfo{X}.lightDistanceSquared, light{X}.vLightFalloff.x, light{X}.vLightFalloff.y); + #endif + #else + preInfo{X}.attenuation = 1.0f; + #endif + + preInfoCoat{X}.attenuation = preInfo{X}.attenuation; + + // Simulates Light radius for diffuse and spec term + // clear coat is using a dedicated roughness + #if defined(HEMILIGHT{X}) || defined(AREALIGHT{X}) + preInfo{X}.roughness = specular_roughness; + preInfoCoat{X}.roughness = coat_roughness; + #else + preInfo{X}.roughness = adjustRoughnessFromLightProperties(specular_roughness, light{X}.vLightSpecular.a, preInfo{X}.lightDistance); + preInfoCoat{X}.roughness = adjustRoughnessFromLightProperties(coat_roughness, light{X}.vLightSpecular.a, preInfoCoat{X}.lightDistance); + #endif + preInfo{X}.diffuseRoughness = base_diffuse_roughness; + preInfo{X}.surfaceAlbedo = base_color.rgb; + #endif +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx new file mode 100644 index 00000000000..d11fb83c00c --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx @@ -0,0 +1,131 @@ +// _____________________________ Base Diffuse Layer IBL _______________________________________ +#ifdef REFLECTION + // Pass in a vector to sample teh irradiance with (to handle reflection or ) + var baseDiffuseEnvironmentLight: vec3f = sampleIrradiance( + normalW + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + , vEnvironmentIrradiance //SH + #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 + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfSampler + , icdfSamplerSampler + #endif + #endif + , uniforms.vReflectionInfos + , viewDirectionW + , base_diffuse_roughness + , base_color + ); + + // _____________________________ Base Specular Layer IBL _______________________________________ + + #ifdef REFLECTIONMAP_3D + var reflectionCoords: vec3f = vec3f(0.f, 0.f, 0.f); + #else + var reflectionCoords: vec2f = vec2f(0.f, 0.f); + #endif + reflectionCoords = createReflectionCoords(fragmentInputs.vPositionW, normalW); + let specularAlphaG: f32 = specular_roughness * specular_roughness; + var baseSpecularEnvironmentLight: vec3f = sampleRadiance(specularAlphaG, uniforms.vReflectionMicrosurfaceInfos.rgb, uniforms.vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , baseGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionSamplerSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #endif + ); + + baseSpecularEnvironmentLight = mix(baseSpecularEnvironmentLight.rgb, baseDiffuseEnvironmentLight, specularAlphaG); + + var coatEnvironmentLight: vec3f = vec3f(0.f, 0.f, 0.f); + if (coat_weight > 0.0) { + #ifdef REFLECTIONMAP_3D + var reflectionCoords: vec3f = vec3f(0.f, 0.f, 0.f); + #else + var reflectionCoords: vec2f = vec2f(0.f, 0.f); + #endif + reflectionCoords = createReflectionCoords(fragmentInputs.vPositionW, coatNormalW); + var coatAlphaG: f32 = coat_roughness * coat_roughness; + coatEnvironmentLight = sampleRadiance(coatAlphaG, uniforms.vReflectionMicrosurfaceInfos.rgb, uniforms.vReflectionInfos + #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) + , coatGeoInfo.NdotVUnclamped + #endif + , reflectionSampler + , reflectionSamplerSampler + , reflectionCoords + #ifdef REALTIME_FILTERING + , uniforms.vReflectionFilteringInfo + #endif + ); + } + + // ______________________________ IBL Fresnel Reflectance ____________________________ + + // Dielectric IBL Fresnel + // The colored fresnel represents the % of light reflected by the base specular lobe + // The non-colored fresnel represents the % of light that doesn't penetrate through + // the base specular lobe. i.e. the specular lobe isn't energy conserving for coloured specular. + let dielectricIblFresnel: f32 = getReflectanceFromBRDFWithEnvLookup(vec3f(baseDielectricReflectance.F0), vec3f(baseDielectricReflectance.F90), baseGeoInfo.environmentBrdf).r; + let dielectricIblColoredFresnel: vec3f = getReflectanceFromBRDFWithEnvLookup(baseDielectricReflectance.coloredF0, baseDielectricReflectance.coloredF90, baseGeoInfo.environmentBrdf); + + // Conductor IBL Fresnel + let conductorIblFresnel: vec3f = conductorIblFresnel(baseConductorReflectance, baseGeoInfo.NdotV, specular_roughness, baseGeoInfo.environmentBrdf); + + // Coat IBL Fresnel + var coatIblFresnel: f32 = 0.0; + if (coat_weight > 0.0) { + coatIblFresnel = getReflectanceFromBRDFWithEnvLookup(vec3f(coatReflectance.F0), vec3f(coatReflectance.F90), coatGeoInfo.environmentBrdf).r; + } + + + var slab_diffuse_ibl: vec3f = vec3f(0., 0., 0.); + var slab_glossy_ibl: vec3f = vec3f(0., 0., 0.); + var slab_metal_ibl: vec3f = vec3f(0., 0., 0.); + var slab_coat_ibl: vec3f = vec3f(0., 0., 0.); + + slab_diffuse_ibl = baseDiffuseEnvironmentLight * uniforms.vLightingIntensity.z; + slab_diffuse_ibl *= aoOut.ambientOcclusionColor; + + // Add the specular environment light + slab_glossy_ibl = baseSpecularEnvironmentLight * uniforms.vLightingIntensity.z; + + // _____________________________ Metal Layer IBL ____________________________ + slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * uniforms.vLightingIntensity.z; + + // _____________________________ Coat Layer IBL _____________________________ + if (coat_weight > 0.0) { + slab_coat_ibl = coatEnvironmentLight * uniforms.vLightingIntensity.z; + } + + // TEMP + var slab_subsurface_ibl: vec3f = vec3f(0., 0., 0.); + var slab_translucent_base_ibl: vec3f = vec3f(0., 0., 0.); + var slab_fuzz_ibl: vec3f = vec3f(0., 0., 0.); + + slab_diffuse_ibl *= base_color.rgb; + + // _____________________________ IBL Material Layer Composition ______________________________________ + #define CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION + let material_opaque_base_ibl: vec3f = mix(slab_diffuse_ibl, slab_subsurface_ibl, subsurface_weight); + let material_dielectric_base_ibl: vec3f = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); + let material_dielectric_gloss_ibl: vec3f = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3f(1.0f), specular_color); + let material_base_substrate_ibl: vec3f = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); + let material_coated_base_ibl: vec3f = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3f(1.0f)); + material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); + +#endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrGeometryInfo.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrGeometryInfo.fx new file mode 100644 index 00000000000..3a778ec483c --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrGeometryInfo.fx @@ -0,0 +1,37 @@ +struct geometryInfoOutParams +{ + NdotV: f32, + NdotVUnclamped: f32, + environmentBrdf: vec3f, + horizonOcclusion: f32, +}; + +#define pbr_inline +fn geometryInfo( + normalW: vec3f, viewDirectionW: vec3f, roughness: f32, geometricNormalW: vec3f +) -> geometryInfoOutParams +{ + var outParams: geometryInfoOutParams; + outParams.NdotVUnclamped = dot(normalW, viewDirectionW); + // The order 1886 page 3. + outParams.NdotV = absEps(outParams.NdotVUnclamped); + + #if defined(ENVIRONMENTBRDF) + // BRDF Lookup + outParams.environmentBrdf = getBRDFLookup(outParams.NdotV, roughness); + #else + outParams.environmentBrdf = vec3f(0.0); + #endif + + outParams.horizonOcclusion = 1.0f; + #if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX) + #ifdef HORIZONOCCLUSION + #if defined(GEOMETRY_NORMAL) || defined(GEOMETRY_COAT_NORMAL) + #ifdef REFLECTIONMAP_3D + outParams.horizonOcclusion = environmentHorizonOcclusion(-viewDirectionW, normalW, geometricNormalW); + #endif + #endif + #endif + #endif + return outParams; +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx index e4d3dceeea3..eb7b52edad8 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx @@ -1,49 +1,128 @@ #ifdef REFLECTION - struct reflectionOutParams - { - environmentRadiance: vec4f - , environmentIrradiance: vec3f - #ifdef REFLECTIONMAP_3D - , reflectionCoords: vec3f - #else - , reflectionCoords: vec2f - #endif - #ifdef SS_TRANSLUCENCY + // _____________________________ Irradiance ________________________________ + // surfaceNormal is the direction to sample. Pass in a refracted vector to sample + // diffusely refracted light. + fn sampleIrradiance( + surfaceNormal: vec3f + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + , vEnvironmentIrradianceSH: vec3f + #endif + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + , iblMatrix: mat4x4f + #endif + #ifdef USEIRRADIANCEMAP + #ifdef REFLECTIONMAP_3D + , irradianceSampler: texture_cube + , irradianceSamplerSampler: sampler + #else + , irradianceSampler: texture_2d + , irradianceSamplerSampler: sampler + #endif + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + , reflectionDominantDirection: vec3f + #endif + #endif + #ifdef REALTIME_FILTERING + , reflectionFilteringInfo: vec2f + #ifdef IBL_CDF_FILTERING + , icdfSampler: texture_2d + , icdfSamplerSampler: sampler + #endif + #endif + , reflectionInfos: vec2f + , viewDirectionW: vec3f + , diffuseRoughness: f32 + , surfaceAlbedo: vec3f + ) -> vec3f { + var environmentIrradiance = vec3f(0., 0., 0.); + + #if (defined(USESPHERICALFROMREFLECTIONMAP) && (!defined(NORMAL) || !defined(USESPHERICALINVERTEX))) || (defined(USEIRRADIANCEMAP) && defined(REFLECTIONMAP_3D)) + var irradianceVector = (iblMatrix * vec4f(surfaceNormal, 0.0f)).xyz; + let irradianceView = (iblMatrix * vec4f(viewDirectionW, 0.0f)).xyz; + #if !defined(USE_IRRADIANCE_DOMINANT_DIRECTION) && !defined(REALTIME_FILTERING) + // Approximate diffuse roughness by bending the surface normal away from the view. + #if BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LAMBERT && BASE_DIFFUSE_MODEL != BRDF_DIFFUSE_MODEL_LEGACY + { + let NdotV = max(dot(surfaceNormal, viewDirectionW), 0.0f); + irradianceVector = mix(irradianceVector, irradianceView, (0.5f * (1.0f - NdotV)) * diffuseRoughness); + } + #endif + #endif + + #ifdef REFLECTIONMAP_OPPOSITEZ + irradianceVector.z *= -1.0f; + #endif + + #ifdef INVERTCUBICMAP + irradianceVector.y *= -1.0f; + #endif + #endif #ifdef USESPHERICALFROMREFLECTIONMAP - #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX) - , irradianceVector: vec3f + #if defined(NORMAL) && defined(USESPHERICALINVERTEX) + environmentIrradiance = vEnvironmentIrradianceSH; + #else + #if defined(REALTIME_FILTERING) + environmentIrradiance = irradiance(reflectionSampler, reflectionSamplerSampler, irradianceVector, reflectionFilteringInfo, diffuseRoughness, surfaceAlbedo, irradianceView + #ifdef IBL_CDF_FILTERING + , icdfSampler + , icdfSamplerSampler + #endif + ); + #else + environmentIrradiance = computeEnvironmentIrradiance(irradianceVector); + #endif + #endif + #elif defined(USEIRRADIANCEMAP) + #ifdef REFLECTIONMAP_3D + let environmentIrradianceFromTexture: vec4f = textureSample(irradianceSampler, irradianceSamplerSampler, irradianceVector); + #else + // TODO: What kind of irradiance map isn't 3D? + let environmentIrradianceFromTexture: vec4f = textureSample(irradianceSampler, irradianceSamplerSampler, reflectionCoords); + #endif + + environmentIrradiance = environmentIrradianceFromTexture.rgb; + #ifdef RGBDREFLECTION + environmentIrradiance.rgb = fromRGBD(environmentIrradianceFromTexture); + #endif + + #ifdef GAMMAREFLECTION + environmentIrradiance.rgb = toLinearSpace(environmentIrradiance.rgb); + #endif + // If we have a predominant light direction, use it to compute the diffuse roughness term.abort + // Otherwise, bend the irradiance vector to simulate retro-reflectivity of diffuse roughness. + #ifdef USE_IRRADIANCE_DOMINANT_DIRECTION + let Ls: vec3f = normalize(reflectionDominantDirection); + let NoL: f32 = dot(irradianceVector, Ls); + let NoV: f32 = dot(irradianceVector, irradianceView); + + var diffuseRoughnessTerm = vec3f(1.0f); + #if BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_EON + let LoV: f32 = dot (Ls, irradianceView); + let mag: f32 = length(reflectionDominantDirection) * 2.0f; + let clampedAlbedo: vec3f = clamp(surfaceAlbedo, vec3f(0.1f), vec3f(1.0f)); + diffuseRoughnessTerm = diffuseBRDF_EON(clampedAlbedo, diffuseRoughness, NoL, NoV, LoV) * PI; + diffuseRoughnessTerm = diffuseRoughnessTerm / clampedAlbedo; + diffuseRoughnessTerm = mix(vec3f(1.0f), diffuseRoughnessTerm, sqrt(clamp(mag * NoV, 0.0f, 1.0f))); + #elif BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_BURLEY + let H: vec3f = (irradianceView + Ls) * 0.5f; + let VoH: f32 = dot(irradianceView, H); + diffuseRoughnessTerm = vec3f(diffuseBRDF_Burley(NoL, NoV, VoH, diffuseRoughness) * PI); + #endif + environmentIrradiance = environmentIrradiance.rgb * diffuseRoughnessTerm; #endif #endif - #endif - }; - #define pbr_inline + environmentIrradiance *= reflectionInfos.x; + return environmentIrradiance; + } + #ifdef REFLECTIONMAP_3D - fn createReflectionCoords( - vPositionW: vec3f, - normalW: vec3f, - #ifdef ANISOTROPIC - anisotropicOut: anisotropicOutParams, - #endif - ) -> vec3f - { - var reflectionCoords: vec3f; + fn createReflectionCoords(vPositionW: vec3f, normalW: vec3f) -> vec3f #else - fn createReflectionCoords( - vPositionW: vec3f, - normalW: vec3f, - #ifdef ANISOTROPIC - anisotropicOut: anisotropicOutParams, - #endif - ) -> vec2f - { - var reflectionCoords: vec2f; + fn createReflectionCoords(vPositionW: vec3f, normalW: vec3f) -> vec2f #endif - #ifdef ANISOTROPIC - var reflectionVector: vec3f = computeReflectionCoords( vec4f(vPositionW, 1.0), anisotropicOut.anisotropicNormal); - #else - var reflectionVector: vec3f = computeReflectionCoords( vec4f(vPositionW, 1.0), normalW); - #endif + { + var reflectionVector: vec3f = computeReflectionCoords(vec4f(vPositionW, 1.0f), normalW); #ifdef REFLECTIONMAP_OPPOSITEZ reflectionVector.z *= -1.0; @@ -51,30 +130,24 @@ // _____________________________ 2D vs 3D Maps ________________________________ #ifdef REFLECTIONMAP_3D - reflectionCoords = reflectionVector; + var reflectionCoords: vec3f = reflectionVector; #else - reflectionCoords = reflectionVector.xy; + var reflectionCoords: vec2f = reflectionVector.xy; #ifdef REFLECTIONMAP_PROJECTION reflectionCoords /= reflectionVector.z; #endif - reflectionCoords.y = 1.0 - reflectionCoords.y; + reflectionCoords.y = 1.0f - reflectionCoords.y; #endif - return reflectionCoords; } - #define pbr_inline - fn sampleReflectionTexture( + fn sampleRadiance( alphaG: f32 - , vReflectionMicrosurfaceInfos: vec3f - , vReflectionInfos: vec2f - , vReflectionColor: vec3f + , reflectionMicrosurfaceInfos: vec3f + , reflectionInfos: vec2f #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) , NdotVUnclamped: f32 #endif - #ifdef LINEARSPECULARREFLECTION - , roughness: f32 - #endif #ifdef REFLECTIONMAP_3D , reflectionSampler: texture_cube , reflectionSamplerSampler: sampler @@ -84,93 +157,54 @@ , reflectionSamplerSampler: sampler , reflectionCoords: vec2f #endif - #ifndef LODBASEDMICROSFURACE - #ifdef REFLECTIONMAP_3D - , reflectionLowSampler: texture_cube - , reflectionLowSamplerSampler: sampler - , reflectionHighSampler: texture_cube - , reflectionHighSamplerSampler: sampler - #else - , reflectionLowSampler: texture_2d - , reflectionLowSamplerSampler: sampler - , reflectionHighSampler: texture_2d - , reflectionHighSamplerSampler: sampler - #endif - #endif #ifdef REALTIME_FILTERING - , vReflectionFilteringInfo: vec2f - #endif - ) -> vec4f - { - var environmentRadiance: vec4f; + , reflectionFilteringInfo: vec2f + #endif + ) -> vec3f { + var environmentRadiance: vec4f = vec4f(0.f, 0.f, 0.f, 0.f); // _____________________________ 2D vs 3D Maps ________________________________ #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX) - var reflectionLOD: f32 = getLodFromAlphaGNdotV(vReflectionMicrosurfaceInfos.x, alphaG, NdotVUnclamped); + var reflectionLOD: f32 = getLodFromAlphaG(reflectionMicrosurfaceInfos.x, alphaG, NdotVUnclamped); #elif defined(LINEARSPECULARREFLECTION) - var reflectionLOD: f32 = getLinearLodFromRoughness(vReflectionMicrosurfaceInfos.x, roughness); + var reflectionLOD: f32 = getLinearLodFromRoughness(reflectionMicrosurfaceInfos.x, roughness); #else - var reflectionLOD: f32 = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG); + var reflectionLOD: f32 = getLodFromAlphaG(reflectionMicrosurfaceInfos.x, alphaG); #endif - #ifdef LODBASEDMICROSFURACE - // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection - reflectionLOD = reflectionLOD * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z; + // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection + reflectionLOD = reflectionLOD * reflectionMicrosurfaceInfos.y + reflectionMicrosurfaceInfos.z; - #ifdef LODINREFLECTIONALPHA - // Automatic LOD adjustment to ensure that the smoothness-based environment LOD selection - // is constrained to appropriate LOD levels in order to prevent aliasing. - // The environment map is first sampled without custom LOD selection to determine - // the hardware-selected LOD, and this is then used to constrain the final LOD selection - // so that excessive surface smoothness does not cause aliasing (e.g. on curved geometry - // where the normal is varying rapidly). - - // Note: Shader Model 4.1 or higher can provide this directly via CalculateLevelOfDetail(), and - // manual calculation via derivatives is also possible, but for simplicity we use the - // hardware LOD calculation with the alpha channel containing the LOD for each mipmap. - var automaticReflectionLOD: f32 = UNPACK_LOD(textureSample(reflectionSampler, reflectionSamplerSampler, reflectionCoords).a); - var requestedReflectionLOD: f32 = max(automaticReflectionLOD, reflectionLOD); - #else - var requestedReflectionLOD: f32 = reflectionLOD; - #endif - #ifdef REALTIME_FILTERING - environmentRadiance = vec4f(radiance(alphaG, reflectionSampler, reflectionSamplerSampler, reflectionCoords, vReflectionFilteringInfo), 1.0); - #else - environmentRadiance = textureSampleLevel(reflectionSampler, reflectionSamplerSampler, reflectionCoords, reflectionLOD); - #endif + #ifdef REALTIME_FILTERING + environmentRadiance = vec4f(radiance(alphaG, reflectionSampler, reflectionSamplerSampler, reflectionCoords, reflectionFilteringInfo), 1.0f); #else - var lodReflectionNormalized: f32 = saturate(reflectionLOD / log2(vReflectionMicrosurfaceInfos.x)); - var lodReflectionNormalizedDoubled: f32 = lodReflectionNormalized * 2.0; - - var environmentMid: vec4f = textureSample(reflectionSampler, reflectionSamplerSampler, reflectionCoords); - if (lodReflectionNormalizedDoubled < 1.0){ - environmentRadiance = mix( - textureSample(reflectionHighSampler, reflectionHighSamplerSampler, reflectionCoords), - environmentMid, - lodReflectionNormalizedDoubled - ); - } else { - environmentRadiance = mix( - environmentMid, - textureSample(reflectionLowSampler, reflectionLowSamplerSampler, reflectionCoords), - lodReflectionNormalizedDoubled - 1.0 - ); - } + environmentRadiance = textureSampleLevel(reflectionSampler, reflectionSamplerSampler, reflectionCoords, reflectionLOD); #endif - var envRadiance = environmentRadiance.rgb; - #ifdef RGBDREFLECTION - envRadiance = fromRGBD(environmentRadiance); + environmentRadiance.rgb = fromRGBD(environmentRadiance); #endif #ifdef GAMMAREFLECTION - envRadiance = toLinearSpaceVec3(environmentRadiance.rgb); + environmentRadiance.rgb = toLinearSpace(environmentRadiance.rgb); #endif // _____________________________ Levels _____________________________________ - envRadiance *= vReflectionInfos.x; - envRadiance *= vReflectionColor.rgb; + // environmentRadiance.rgb *= reflectionInfos.xxx; + return environmentRadiance.rgb; + } - return vec4f(envRadiance, environmentRadiance.a); + fn conductorIblFresnel(reflectance: ReflectanceParams, NdotV: f32, roughness: f32, environmentBrdf: vec3f) -> vec3f + { + #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 reflectanceOut 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. + return getF82Specular(NdotV, reflectance.coloredF0, reflectance.coloredF90, roughness); + #else + return getReflectanceFromBRDFLookup(reflectance.coloredF0, reflectance.coloredF90, environmentBrdf); + #endif } #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js deleted file mode 100644 index 8963b3b5be0..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js +++ /dev/null @@ -1,63 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapFragment"; -const shader = `var uvOffset: vec2f= vec2f(0.0,0.0); -#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL) -#ifdef NORMALXYSCALE -var normalScale: f32=1.0; -#elif defined(GEOMETRY_NORMAL) -var normalScale: f32=uniforms.vGeometryNormalInfos.y; -#else -var normalScale: f32=1.0; -#endif -#if defined(TANGENT) && defined(NORMAL) -var TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); -#elif defined(GEOMETRY_NORMAL) -var TBNUV: vec2f=select(-fragmentInputs.vGeometryNormalUV,fragmentInputs.vGeometryNormalUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV,uniforms.vTangentSpaceParams); -#else -var TBNUV: vec2f=select(-fragmentInputs.vDetailUV,fragmentInputs.vDetailUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV, vec2f(1.,1.)); -#endif -#elif defined(ANISOTROPIC) -#if defined(TANGENT) && defined(NORMAL) -var TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); -#else -var TBNUV: vec2f=select( -fragmentInputs.vMainUV1,fragmentInputs.vMainUV1,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW,input.vPositionW,TBNUV, vec2f(1.,1.)); -#endif -#endif -#ifdef PARALLAX -var invTBN: mat3x3f=transposeMat3(TBN); -#ifdef PARALLAXOCCLUSION -uvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,fragmentInputs.vGeometryNormalUV,uniforms.vGeometryNormalInfos.z); -#else -uvOffset=parallaxOffset(invTBN*viewDirectionW,uniforms.vGeometryNormalInfos.z); -#endif -#endif -#ifdef DETAIL -var detailColor: vec4f=textureSample(detailSampler,detailSamplerSampler,fragmentInputs.vDetailUV+uvOffset);var detailNormalRG: vec2f=detailColor.wy*2.0-1.0;var detailNormalB: f32=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));var detailNormal: vec3f= vec3f(detailNormalRG,detailNormalB); -#endif -#ifdef GEOMETRY_NORMAL -#ifdef OBJECTSPACE_NORMALMAP -#define CUSTOM_FRAGMENT_BUMP_FRAGMENT -normalW=normalize(textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3x3f(uniforms.normalMatrix[0].xyz,uniforms.normalMatrix[1].xyz,uniforms.normalMatrix[2].xyz)*normalW); -#elif !defined(DETAIL) -normalW=perturbNormal(TBN,textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz,uniforms.vGeometryNormalInfos.y); -#else -var bumpNormal: vec3f=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz*2.0-1.0; -#if DETAIL_NORMALBLENDMETHOD==0 -detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);var blendedNormal: vec3f=normalize( vec3f(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z)); -#elif DETAIL_NORMALBLENDMETHOD==1 -detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);bumpNormal+= vec3f(0.0,0.0,1.0);detailNormal*= vec3f(-1.0,-1.0,1.0);var blendedNormal: vec3f=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal; -#endif -normalW=perturbNormalBase(TBN,blendedNormal,uniforms.vGeometryNormalInfos.y); -#endif -#elif defined(DETAIL) -detailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);normalW=perturbNormalBase(TBN,detailNormal,uniforms.vDetailInfos.z); -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStoreWGSL[name]) { - ShaderStore.IncludesShadersStoreWGSL[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragmentWGSL = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragment.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map deleted file mode 100644 index 5ec48fd9e3d..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragment.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragment.js","sourceRoot":"","sources":["openpbrNormalMapFragment.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,0BAA0B,CAAC;AACxC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragment\";\nconst shader = `var uvOffset: vec2f= vec2f(0.0,0.0);\n#if defined(GEOMETRY_NORMAL) || defined(PARALLAX) || defined(DETAIL)\n#ifdef NORMALXYSCALE\nvar normalScale: f32=1.0;\n#elif defined(GEOMETRY_NORMAL)\nvar normalScale: f32=uniforms.vGeometryNormalInfos.y;\n#else\nvar normalScale: f32=1.0;\n#endif\n#if defined(TANGENT) && defined(NORMAL)\nvar TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); \n#elif defined(GEOMETRY_NORMAL)\nvar TBNUV: vec2f=select(-fragmentInputs.vGeometryNormalUV,fragmentInputs.vGeometryNormalUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV,uniforms.vTangentSpaceParams);\n#else\nvar TBNUV: vec2f=select(-fragmentInputs.vDetailUV,fragmentInputs.vDetailUV,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW*normalScale,input.vPositionW,TBNUV, vec2f(1.,1.));\n#endif\n#elif defined(ANISOTROPIC)\n#if defined(TANGENT) && defined(NORMAL)\nvar TBN: mat3x3f=mat3x3(input.vTBN0,input.vTBN1,input.vTBN2); \n#else\nvar TBNUV: vec2f=select( -fragmentInputs.vMainUV1,fragmentInputs.vMainUV1,fragmentInputs.frontFacing);var TBN: mat3x3f=cotangent_frame(normalW,input.vPositionW,TBNUV, vec2f(1.,1.));\n#endif\n#endif\n#ifdef PARALLAX\nvar invTBN: mat3x3f=transposeMat3(TBN);\n#ifdef PARALLAXOCCLUSION\nuvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,fragmentInputs.vGeometryNormalUV,uniforms.vGeometryNormalInfos.z);\n#else\nuvOffset=parallaxOffset(invTBN*viewDirectionW,uniforms.vGeometryNormalInfos.z);\n#endif\n#endif\n#ifdef DETAIL\nvar detailColor: vec4f=textureSample(detailSampler,detailSamplerSampler,fragmentInputs.vDetailUV+uvOffset);var detailNormalRG: vec2f=detailColor.wy*2.0-1.0;var detailNormalB: f32=sqrt(1.-saturate(dot(detailNormalRG,detailNormalRG)));var detailNormal: vec3f= vec3f(detailNormalRG,detailNormalB);\n#endif\n#ifdef GEOMETRY_NORMAL\n#ifdef OBJECTSPACE_NORMALMAP\n#define CUSTOM_FRAGMENT_BUMP_FRAGMENT\nnormalW=normalize(textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).xyz *2.0-1.0);normalW=normalize(mat3x3f(uniforms.normalMatrix[0].xyz,uniforms.normalMatrix[1].xyz,uniforms.normalMatrix[2].xyz)*normalW);\n#elif !defined(DETAIL)\nnormalW=perturbNormal(TBN,textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz,uniforms.vGeometryNormalInfos.y);\n#else\nvar bumpNormal: vec3f=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV+uvOffset).xyz*2.0-1.0;\n#if DETAIL_NORMALBLENDMETHOD==0 \ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);var blendedNormal: vec3f=normalize( vec3f(bumpNormal.xy+detailNormal.xy,bumpNormal.z*detailNormal.z));\n#elif DETAIL_NORMALBLENDMETHOD==1 \ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);bumpNormal+= vec3f(0.0,0.0,1.0);detailNormal*= vec3f(-1.0,-1.0,1.0);var blendedNormal: vec3f=bumpNormal*dot(bumpNormal,detailNormal)/bumpNormal.z-detailNormal;\n#endif\nnormalW=perturbNormalBase(TBN,blendedNormal,uniforms.vGeometryNormalInfos.y);\n#endif\n#elif defined(DETAIL)\ndetailNormal=vec3f(detailNormal.xy*uniforms.vDetailInfos.z,detailNormal.z);normalW=perturbNormalBase(TBN,detailNormal,uniforms.vDetailInfos.z);\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js deleted file mode 100644 index 4c7afb24c09..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js +++ /dev/null @@ -1,42 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -import "./samplerFragmentDeclaration"; -const name = "openpbrNormalMapFragmentFunctions"; -const shader = `#if defined(GEOMETRY_NORMAL) -#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) -#endif -#if defined(DETAIL) -#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) -#endif -#if defined(GEOMETRY_NORMAL) && defined(PARALLAX) -const minSamples: f32=4.;const maxSamples: f32=15.;const iMaxSamples: i32=15;fn parallaxOcclusion(vViewDirCoT: vec3f,vNormalCoT: vec3f,texCoord: vec2f,parallaxScale: f32)->vec2f {var parallaxLimit: f32=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;var vOffsetDir: vec2f=normalize(vViewDirCoT.xy);var vMaxOffset: vec2f=vOffsetDir*parallaxLimit;var numSamples: f32=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));var stepSize: f32=1.0/numSamples;var currRayHeight: f32=1.0;var vCurrOffset: vec2f= vec2f(0,0);var vLastOffset: vec2f= vec2f(0,0);var lastSampledHeight: f32=1.0;var currSampledHeight: f32=1.0;var keepWorking: bool=true;for (var i: i32=0; icurrRayHeight) -{var delta1: f32=currSampledHeight-currRayHeight;var delta2: f32=(currRayHeight+stepSize)-lastSampledHeight;var ratio: f32=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;} -else -{currRayHeight-=stepSize;vLastOffset=vCurrOffset; -#ifdef PARALLAX_RHS -vCurrOffset-=stepSize*vMaxOffset; -#else -vCurrOffset+=stepSize*vMaxOffset; -#endif -lastSampledHeight=currSampledHeight;}} -return vCurrOffset;} -fn parallaxOffset(viewDir: vec3f,heightScale: f32)->vec2f -{var height: f32=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).w;var texCoordOffset: vec2f=heightScale*viewDir.xy*height; -#ifdef PARALLAX_RHS -return texCoordOffset; -#else -return -texCoordOffset; -#endif -} -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStoreWGSL[name]) { - ShaderStore.IncludesShadersStoreWGSL[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragmentFunctionsWGSL = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragmentFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map deleted file mode 100644 index 9152b6cb7f5..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragmentFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,8BAA8B,CAAC;AAEtC,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\nimport \"./samplerFragmentDeclaration\";\n\nconst name = \"openpbrNormalMapFragmentFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL)\n#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal)\n#endif\n#if defined(DETAIL)\n#include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail)\n#endif\n#if defined(GEOMETRY_NORMAL) && defined(PARALLAX)\nconst minSamples: f32=4.;const maxSamples: f32=15.;const iMaxSamples: i32=15;fn parallaxOcclusion(vViewDirCoT: vec3f,vNormalCoT: vec3f,texCoord: vec2f,parallaxScale: f32)->vec2f {var parallaxLimit: f32=length(vViewDirCoT.xy)/vViewDirCoT.z;parallaxLimit*=parallaxScale;var vOffsetDir: vec2f=normalize(vViewDirCoT.xy);var vMaxOffset: vec2f=vOffsetDir*parallaxLimit;var numSamples: f32=maxSamples+(dot(vViewDirCoT,vNormalCoT)*(minSamples-maxSamples));var stepSize: f32=1.0/numSamples;var currRayHeight: f32=1.0;var vCurrOffset: vec2f= vec2f(0,0);var vLastOffset: vec2f= vec2f(0,0);var lastSampledHeight: f32=1.0;var currSampledHeight: f32=1.0;var keepWorking: bool=true;for (var i: i32=0; icurrRayHeight)\n{var delta1: f32=currSampledHeight-currRayHeight;var delta2: f32=(currRayHeight+stepSize)-lastSampledHeight;var ratio: f32=delta1/(delta1+delta2);vCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;keepWorking=false;}\nelse\n{currRayHeight-=stepSize;vLastOffset=vCurrOffset;\n#ifdef PARALLAX_RHS\nvCurrOffset-=stepSize*vMaxOffset;\n#else\nvCurrOffset+=stepSize*vMaxOffset;\n#endif\nlastSampledHeight=currSampledHeight;}}\nreturn vCurrOffset;}\nfn parallaxOffset(viewDir: vec3f,heightScale: f32)->vec2f\n{var height: f32=textureSample(geometryNormalSampler,geometryNormalSamplerSampler,fragmentInputs.vGeometryNormalUV).w;var texCoordOffset: vec2f=heightScale*viewDir.xy*height;\n#ifdef PARALLAX_RHS\nreturn texCoordOffset;\n#else\nreturn -texCoordOffset;\n#endif\n}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentFunctionsWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js deleted file mode 100644 index 39b39ef3f1a..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js +++ /dev/null @@ -1,51 +0,0 @@ -// Do not edit. -import { ShaderStore } from "../../Engines/shaderStore"; -const name = "openpbrNormalMapFragmentMainFunctions"; -const shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL) -#if defined(TANGENT) && defined(NORMAL) -varying vTBN0: vec3f;varying vTBN1: vec3f;varying vTBN2: vec3f; -#endif -#ifdef OBJECTSPACE_NORMALMAP -uniform normalMatrix: mat4x4f;fn toNormalMatrix(m: mat4x4f)->mat4x4f -{var a00=m[0][0];var a01=m[0][1];var a02=m[0][2];var a03=m[0][3];var a10=m[1][0];var a11=m[1][1];var a12=m[1][2];var a13=m[1][3];var a20=m[2][0]; -var a21=m[2][1];var a22=m[2][2];var a23=m[2][3];var a30=m[3][0]; -var a31=m[3][1];var a32=m[3][2];var a33=m[3][3];var b00=a00*a11-a01*a10;var b01=a00*a12-a02*a10;var b02=a00*a13-a03*a10;var b03=a01*a12-a02*a11;var b04=a01*a13-a03*a11;var b05=a02*a13-a03*a12;var b06=a20*a31-a21*a30;var b07=a20*a32-a22*a30;var b08=a20*a33-a23*a30;var b09=a21*a32-a22*a31;var b10=a21*a33-a23*a31;var b11=a22*a33-a23*a32;var det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;var mi=mat4x4( -(a11*b11-a12*b10+a13*b09)/det, -(a02*b10-a01*b11-a03*b09)/det, -(a31*b05-a32*b04+a33*b03)/det, -(a22*b04-a21*b05-a23*b03)/det, -(a12*b08-a10*b11-a13*b07)/det, -(a00*b11-a02*b08+a03*b07)/det, -(a32*b02-a30*b05-a33*b01)/det, -(a20*b05-a22*b02+a23*b01)/det, -(a10*b10-a11*b08+a13*b06)/det, -(a01*b08-a00*b10-a03*b06)/det, -(a30*b04-a31*b02+a33*b00)/det, -(a21*b02-a20*b04-a23*b00)/det, -(a11*b07-a10*b09-a12*b06)/det, -(a00*b09-a01*b07+a02*b06)/det, -(a31*b01-a30*b03-a32*b00)/det, -(a20*b03-a21*b01+a22*b00)/det);return mat4x4(mi[0][0],mi[1][0],mi[2][0],mi[3][0], -mi[0][1],mi[1][1],mi[2][1],mi[3][1], -mi[0][2],mi[1][2],mi[2][2],mi[3][2], -mi[0][3],mi[1][3],mi[2][3],mi[3][3]);} -#endif -fn perturbNormalBase(cotangentFrame: mat3x3f,normal: vec3f,scale: f32)->vec3f -{var output=normal; -#ifdef NORMALXYSCALE -output=normalize(output* vec3f(scale,scale,1.0)); -#endif -return normalize(cotangentFrame*output);} -fn perturbNormal(cotangentFrame: mat3x3f,textureSample: vec3f,scale: f32)->vec3f -{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);} -fn cotangent_frame(normal: vec3f,p: vec3f,uv: vec2f,tangentSpaceParams: vec2f)->mat3x3f -{var dp1: vec3f=dpdx(p);var dp2: vec3f=dpdy(p);var duv1: vec2f=dpdx(uv);var duv2: vec2f=dpdy(uv);var dp2perp: vec3f=cross(dp2,normal);var dp1perp: vec3f=cross(normal,dp1);var tangent: vec3f=dp2perp*duv1.x+dp1perp*duv2.x;var bitangent: vec3f=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;var det: f32=max(dot(tangent,tangent),dot(bitangent,bitangent));var invmax: f32=select(inverseSqrt(det),0.0,det==0.0);return mat3x3f(tangent*invmax,bitangent*invmax,normal);} -#endif -`; -// Sideeffect -if (!ShaderStore.IncludesShadersStoreWGSL[name]) { - ShaderStore.IncludesShadersStoreWGSL[name] = shader; -} -/** @internal */ -export const openpbrNormalMapFragmentMainFunctionsWGSL = { name, shader }; -//# sourceMappingURL=openpbrNormalMapFragmentMainFunctions.js.map \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map deleted file mode 100644 index 34b5ae01659..00000000000 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentMainFunctions.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openpbrNormalMapFragmentMainFunctions.js","sourceRoot":"","sources":["openpbrNormalMapFragmentMainFunctions.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,IAAI,GAAG,uCAAuC,CAAC;AACrD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCd,CAAC;AACF,aAAa;AACb,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,WAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACxD,CAAC;AACD,gBAAgB;AAChB,MAAM,CAAC,MAAM,yCAAyC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["// Do not edit.\nimport { ShaderStore } from \"../../Engines/shaderStore\";\n\nconst name = \"openpbrNormalMapFragmentMainFunctions\";\nconst shader = `#if defined(GEOMETRY_NORMAL) || defined(CLEARCOAT_BUMP) || defined(ANISOTROPIC) || defined(DETAIL)\n#if defined(TANGENT) && defined(NORMAL) \nvarying vTBN0: vec3f;varying vTBN1: vec3f;varying vTBN2: vec3f;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\nuniform normalMatrix: mat4x4f;fn toNormalMatrix(m: mat4x4f)->mat4x4f\n{var a00=m[0][0];var a01=m[0][1];var a02=m[0][2];var a03=m[0][3];var a10=m[1][0];var a11=m[1][1];var a12=m[1][2];var a13=m[1][3];var a20=m[2][0]; \nvar a21=m[2][1];var a22=m[2][2];var a23=m[2][3];var a30=m[3][0]; \nvar a31=m[3][1];var a32=m[3][2];var a33=m[3][3];var b00=a00*a11-a01*a10;var b01=a00*a12-a02*a10;var b02=a00*a13-a03*a10;var b03=a01*a12-a02*a11;var b04=a01*a13-a03*a11;var b05=a02*a13-a03*a12;var b06=a20*a31-a21*a30;var b07=a20*a32-a22*a30;var b08=a20*a33-a23*a30;var b09=a21*a32-a22*a31;var b10=a21*a33-a23*a31;var b11=a22*a33-a23*a32;var det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;var mi=mat4x4(\n(a11*b11-a12*b10+a13*b09)/det,\n(a02*b10-a01*b11-a03*b09)/det,\n(a31*b05-a32*b04+a33*b03)/det,\n(a22*b04-a21*b05-a23*b03)/det,\n(a12*b08-a10*b11-a13*b07)/det,\n(a00*b11-a02*b08+a03*b07)/det,\n(a32*b02-a30*b05-a33*b01)/det,\n(a20*b05-a22*b02+a23*b01)/det,\n(a10*b10-a11*b08+a13*b06)/det,\n(a01*b08-a00*b10-a03*b06)/det,\n(a30*b04-a31*b02+a33*b00)/det,\n(a21*b02-a20*b04-a23*b00)/det,\n(a11*b07-a10*b09-a12*b06)/det,\n(a00*b09-a01*b07+a02*b06)/det,\n(a31*b01-a30*b03-a32*b00)/det,\n(a20*b03-a21*b01+a22*b00)/det);return mat4x4(mi[0][0],mi[1][0],mi[2][0],mi[3][0],\nmi[0][1],mi[1][1],mi[2][1],mi[3][1],\nmi[0][2],mi[1][2],mi[2][2],mi[3][2],\nmi[0][3],mi[1][3],mi[2][3],mi[3][3]);}\n#endif\nfn perturbNormalBase(cotangentFrame: mat3x3f,normal: vec3f,scale: f32)->vec3f\n{var output=normal;\n#ifdef NORMALXYSCALE\noutput=normalize(output* vec3f(scale,scale,1.0));\n#endif\nreturn normalize(cotangentFrame*output);}\nfn perturbNormal(cotangentFrame: mat3x3f,textureSample: vec3f,scale: f32)->vec3f\n{return perturbNormalBase(cotangentFrame,textureSample*2.0-1.0,scale);}\nfn cotangent_frame(normal: vec3f,p: vec3f,uv: vec2f,tangentSpaceParams: vec2f)->mat3x3f\n{var dp1: vec3f=dpdx(p);var dp2: vec3f=dpdy(p);var duv1: vec2f=dpdx(uv);var duv2: vec2f=dpdy(uv);var dp2perp: vec3f=cross(dp2,normal);var dp1perp: vec3f=cross(normal,dp1);var tangent: vec3f=dp2perp*duv1.x+dp1perp*duv2.x;var bitangent: vec3f=dp2perp*duv1.y+dp1perp*duv2.y;tangent*=tangentSpaceParams.x;bitangent*=tangentSpaceParams.y;var det: f32=max(dot(tangent,tangent),dot(bitangent,bitangent));var invmax: f32=select(inverseSqrt(det),0.0,det==0.0);return mat3x3f(tangent*invmax,bitangent*invmax,normal);}\n#endif\n`;\n// Sideeffect\nif (!ShaderStore.IncludesShadersStoreWGSL[name]) {\n ShaderStore.IncludesShadersStoreWGSL[name] = shader;\n}\n/** @internal */\nexport const openpbrNormalMapFragmentMainFunctionsWGSL = { name, shader };\n"]} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 49da7c0249d..6dbcacbf487 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -44,11 +44,18 @@ #define CUSTOM_FRAGMENT_DEFINITIONS -#include -#include -#include -#include +#include +#include + +// #include #include +#include + +// Do a mix between layers with additional multipliers for each layer. +fn layer(slab_bottom: vec3f, slab_top: vec3f, lerp_factor: f32, bottom_multiplier: vec3f, top_multiplier: vec3f) -> vec3f { + + return mix(slab_bottom * bottom_multiplier, slab_top * top_multiplier, lerp_factor); +} // _____________________________ MAIN FUNCTION ____________________________ @fragment @@ -60,57 +67,22 @@ fn main(input: FragmentInputs) -> FragmentOutputs { // _____________________________ Geometry Information ____________________________ #include + var coatNormalW: vec3f = normalW; #include - #include - - // _____________________________ Albedo & Opacity ______________________________ - var albedoOpacityOut: albedoOpacityOutParams; - -#ifdef BASE_COLOR - var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, fragmentInputs.vBaseColorUV + uvOffset); -#endif + #include -#ifdef BASE_WEIGHT - var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, fragmentInputs.vBaseWeightUV + uvOffset); -#endif + // ______________________ Read Base properties & Opacity ______________________________ + #include -#ifdef OPACITY - var opacityMap: vec4f = textureSample(opacitySampler, opacitySamplerSampler, fragmentInputs.vOpacityUV + uvOffset); -#endif + // _____________________________ Read Coat Layer properties ______________________ + #include -#ifdef DECAL - var decalColor: vec4f = textureSample(decalSampler, decalSamplerSampler, fragmentInputs.vDecalUV + uvOffset); -#endif - - albedoOpacityOut = albedoOpacityBlock( - uniforms.vBaseColor - #ifdef BASE_COLOR - , baseColorFromTexture - , uniforms.vBaseColorInfos - #endif - , uniforms.vBaseWeight - #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; + // TEMP + var subsurface_weight: f32 = 0.0f; + var transmission_weight: f32 = 0.0f; + var fuzz_weight: f32 = 0.0f; #define CUSTOM_FRAGMENT_UPDATE_ALPHA @@ -132,185 +104,75 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif ); -#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 + // _____________________________ Compute Geometry info for coat layer _________________________ + let coatGeoInfo: geometryInfoOutParams = geometryInfo( + coatNormalW, viewDirectionW.xyz, coat_roughness, geometricNormalW + ); - 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 + // _____________________________ Compute Geometry info for base layer _________________________ + // Adjust the base roughness to account for the coat layer. Equation 61 in OpenPBR spec. + specular_roughness = mix(specular_roughness, pow(min(1.0f, pow(specular_roughness, 4.0f) + 2.0f * pow(coat_roughness, 4.0f)), 0.25f), coat_weight); + let baseGeoInfo: geometryInfoOutParams = geometryInfo( + normalW, viewDirectionW.xyz, specular_roughness, geometricNormalW + ); - // 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 + // _______________________ F0 and F90 Reflectance _______________________________ + + // Coat + let coatReflectance: ReflectanceParams = dielectricReflectance( + coat_ior // inside IOR + , 1.0f // outside IOR is air + , vec3f(1.0f) + , coat_weight + ); - 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 + // Base Dielectric + let baseDielectricReflectance: ReflectanceParams = dielectricReflectance( + specular_ior // inside IOR + , mix(1.0f, coat_ior, coat_weight) // outside IOR is coat + , specular_color + , specular_weight ); - var roughness: f32 = reflectivityOut.roughness; - var diffuseRoughness: f32 = reflectivityOut.diffuseRoughness; + // Base Metallic + let baseConductorReflectance: ReflectanceParams = conductorReflectance(base_color, specular_color, specular_weight); - #if defined(METALLIC_ROUGHNESS) && defined(AOSTOREINMETALMAPRED) - aoOut.ambientOcclusionColor = reflectivityOut.ambientOcclusionColor; - #endif + // ________________________ Environment (IBL) Lighting ____________________________ + var material_surface_ibl: vec3f = vec3f(0.f, 0.f, 0.f); + #include - // _____________________________ 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 + // __________________________ Direct Lighting ____________________________ + var material_surface_direct: vec3f = vec3f(0.f, 0.f, 0.f); + #if defined(LIGHT0) + var aggShadow: f32 = 0.f; + var numLights: f32 = 0.f; + #include[0..maxSimultaneousLights] + #include[0..maxSimultaneousLights] + #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; + // _________________________ Emissive Lighting _______________________________ + var material_surface_emission: vec3f = uniforms.vEmissionColor; #ifdef EMISSION_COLOR - var emissionColorTex: vec3f = textureSample(emissionColorSampler, emissionColorSamplerSampler, fragmentInputs.vEmissionColorUV + uvOffset).rgb; + let emissionColorTex: vec3f = textureSample(emissionColorSampler, emissionColorSamplerSampler, uniforms.vEmissionColorUV + uvOffset).rgb; #ifdef EMISSION_COLOR_GAMMA - finalEmission *= toLinearSpaceVec3(emissionColorTex.rgb); + material_surface_emission *= toLinearSpace(emissionColorTex.rgb); #else - finalEmission *= emissionColorTex.rgb; + material_surface_emission *= emissionColorTex.rgb; #endif - finalEmission *= uniforms.vEmissionColorInfos.y; - #endif - finalEmission *= uniforms.vLightingIntensity.y; - - // ______________________________ Ambient ________________________________________ - #ifdef AMBIENT_OCCLUSION - finalDiffuse *= mix( vec3f(1.), aoOut.ambientOcclusionColor, 1.0 - uniforms.vAmbientOcclusionInfos.y); + material_surface_emission *= uniforms.vEmissionColorInfos.y; #endif + material_surface_emission *= uniforms.vLightingIntensity.y; + // _____________________________ Final Color Composition ________________________ #define CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION - #include + var finalColor: vec4f = vec4f(material_surface_ibl + material_surface_direct + material_surface_emission, alpha); + + #define CUSTOM_FRAGMENT_BEFORE_FOG + + // _____________________________ Finally ___________________________________________ + finalColor = max(finalColor, vec4f(0.0)); #include #include(color, finalColor) From 081444979e2f4761993400505180559037a01dfd Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 4 Aug 2025 17:25:19 -0700 Subject: [PATCH 31/45] Fix AO compilation errors for OpenPBR --- .../openpbrBlockAmbientOcclusion.fx | 34 ++++++++++++++++++ .../dev/core/src/Shaders/openpbr.fragment.fx | 2 +- .../ShadersInclude/openpbrBaseLayerData.fx | 16 ++++----- .../openpbrBlockAmbientOcclusion.fx | 35 +++++++++++++++++++ .../ShadersInclude/openpbrCoatLayerData.fx | 10 +++--- .../openpbrFragmentSamplersDeclaration.fx | 1 - .../openpbrNormalMapFragmentFunctions.fx | 4 +++ .../core/src/ShadersWGSL/openpbr.fragment.fx | 2 +- 8 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx create mode 100644 packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx new file mode 100644 index 00000000000..ed33ed5cc7b --- /dev/null +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBlockAmbientOcclusion.fx @@ -0,0 +1,34 @@ +struct ambientOcclusionOutParams +{ + vec3 ambientOcclusionColor; +#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) + vec3 ambientOcclusionColorMap; +#endif +}; + +ambientOcclusionOutParams ambientOcclusionBlock( +#ifdef AMBIENT_OCCLUSION + in vec3 ambientOcclusionColorMap_, + in vec2 ambientInfos +#endif +) +{ + ambientOcclusionOutParams outParams; + vec3 ambientOcclusionColor = vec3(1., 1., 1.); + + #ifdef AMBIENT_OCCLUSION + vec3 ambientOcclusionColorMap = ambientOcclusionColorMap_ * ambientInfos.y; + #ifdef AMBIENTINGRAYSCALE + ambientOcclusionColorMap = vec3(ambientOcclusionColorMap.r, ambientOcclusionColorMap.r, ambientOcclusionColorMap.r); + #endif + // ambientOcclusionColor = mix(ambientOcclusionColor, ambientOcclusionColorMap, ambientInfos.z); + + #if DEBUGMODE > 0 + outParams.ambientOcclusionColorMap = ambientOcclusionColorMap; + #endif + #endif + + outParams.ambientOcclusionColor = ambientOcclusionColor; + + return outParams; +} diff --git a/packages/dev/core/src/Shaders/openpbr.fragment.fx b/packages/dev/core/src/Shaders/openpbr.fragment.fx index b0d9ce09031..b4dfe4c6b4a 100644 --- a/packages/dev/core/src/Shaders/openpbr.fragment.fx +++ b/packages/dev/core/src/Shaders/openpbr.fragment.fx @@ -63,7 +63,7 @@ precision highp float; #include #include -// #include +#include #include #include diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx index 2354074a462..ed78ab57fbc 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx @@ -18,38 +18,38 @@ var alpha: f32 = 1.0; // Sample Base Layer properties from textures #ifdef BASE_WEIGHT - var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, uniforms.vBaseWeightUV + uvOffset); + var baseWeightFromTexture: vec4f = textureSample(baseWeightSampler, baseWeightSamplerSampler, fragmentInputs.vBaseWeightUV + uvOffset); #endif #ifdef BASE_COLOR - var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, uniforms.vBaseColorUV + uvOffset); + var baseColorFromTexture: vec4f = textureSample(baseColorSampler, baseColorSamplerSampler, fragmentInputs.vBaseColorUV + uvOffset); #endif #ifdef METALLIC_ROUGHNESS - var metallicRoughnessFromTexture: vec4f = textureSample(baseMetalRoughSampler, baseMetalRoughSamplerSampler, uniforms.vBaseMetalRoughUV + uvOffset); + var metallicRoughnessFromTexture: vec4f = textureSample(baseMetalRoughSampler, baseMetalRoughSamplerSampler, fragmentInputs.vBaseMetalRoughUV + uvOffset); #endif #ifdef BASE_DIFFUSE_ROUGHNESS - var baseDiffuseRoughnessFromTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, uniforms.vBaseDiffuseRoughnessUV + uvOffset).r; + var baseDiffuseRoughnessFromTexture: f32 = textureSample(baseDiffuseRoughnessSampler, baseDiffuseRoughnessSamplerSampler, fragmentInputs.vBaseDiffuseRoughnessUV + uvOffset).r; #endif #ifdef GEOMETRY_OPACITY - var opacityFromTexture: vec4f = textureSample(opacitySampler, opacitySamplerSampler, uniforms.vOpacityUV + uvOffset); + var opacityFromTexture: vec4f = textureSample(opacitySampler, opacitySamplerSampler, fragmentInputs.vOpacityUV + uvOffset); #endif #ifdef DECAL - var decalFromTexture: vec4f = textureSample(decalSampler, decalSamplerSampler, uniforms.vDecalUV + uvOffset); + var decalFromTexture: vec4f = textureSample(decalSampler, decalSamplerSampler, fragmentInputs.vDecalUV + uvOffset); #endif #ifdef SPECULAR_COLOR - var specularColorFromTexture: vec4f = textureSample(specularColorSampler, specularColorSamplerSampler, uniforms.vSpecularColorUV + uvOffset); + var specularColorFromTexture: vec4f = textureSample(specularColorSampler, specularColorSamplerSampler, fragmentInputs.vSpecularColorUV + uvOffset); #ifdef SPECULAR_COLOR_GAMMA specularColorFromTexture = toLinearSpace(specularColorFromTexture.rgb); #endif #endif #ifdef SPECULAR_WEIGHT - var specularWeightFromTexture: vec4f = textureSample(specularWeightSampler, specularWeightSamplerSampler, uniforms.vSpecularWeightUV + uvOffset); + var specularWeightFromTexture: vec4f = textureSample(specularWeightSampler, specularWeightSamplerSampler, fragmentInputs.vSpecularWeightUV + uvOffset); #endif // Initalize base layer properties from uniforms diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx new file mode 100644 index 00000000000..a514b930308 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBlockAmbientOcclusion.fx @@ -0,0 +1,35 @@ +struct ambientOcclusionOutParams +{ + ambientOcclusionColor: vec3f, +#if DEBUGMODE > 0 && defined(AMBIENT_OCCLUSION) + ambientOcclusionColorMap: vec3f +#endif +}; + +#define pbr_inline +fn ambientOcclusionBlock( +#ifdef AMBIENT_OCCLUSION + ambientOcclusionColorMap_: vec3f, + ambientInfos: vec2f +#endif +) -> ambientOcclusionOutParams +{ + var outParams: ambientOcclusionOutParams; + var ambientOcclusionColor: vec3f = vec3f(1., 1., 1.); + + #ifdef AMBIENT_OCCLUSION + var ambientOcclusionColorMap: vec3f = ambientOcclusionColorMap_ * ambientInfos.y; + #ifdef AMBIENTINGRAYSCALE + ambientOcclusionColorMap = vec3f(ambientOcclusionColorMap.r, ambientOcclusionColorMap.r, ambientOcclusionColorMap.r); + #endif + // ambientOcclusionColor = mix(ambientOcclusionColor, ambientOcclusionColorMap, ambientInfos.z); + + #if DEBUGMODE > 0 + outParams.ambientOcclusionColorMap = ambientOcclusionColorMap; + #endif + #endif + + outParams.ambientOcclusionColor = ambientOcclusionColor; + + return outParams; +} diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx index c76ea84100f..7ccdee198ec 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx @@ -10,23 +10,23 @@ var coat_darkening: f32 = 1.0f; // Sample Coat Layer properties from textures #ifdef COAT_WEIGHT - var coatWeightFromTexture: vec4f = textureSample(coatWeightSampler, coatWeightSamplerSampler, uniforms.vCoatWeightUV + uvOffset); + var coatWeightFromTexture: vec4f = textureSample(coatWeightSampler, coatWeightSamplerSampler, fragmentInputs.vCoatWeightUV + uvOffset); #endif #ifdef COAT_COLOR - var coatColorFromTexture: vec4f = textureSample(coatColorSampler, coatColorSamplerSampler, uniforms.vCoatColorUV + uvOffset); + var coatColorFromTexture: vec4f = textureSample(coatColorSampler, coatColorSamplerSampler, fragmentInputs.vCoatColorUV + uvOffset); #endif #ifdef COAT_ROUGHNESS - var coatRoughnessFromTexture: vec4f = textureSample(coatRoughnessSampler, coatRoughnessSamplerSampler, uniforms.vCoatRoughnessUV + uvOffset); + var coatRoughnessFromTexture: vec4f = textureSample(coatRoughnessSampler, coatRoughnessSamplerSampler, fragmentInputs.vCoatRoughnessUV + uvOffset); #endif #ifdef COAT_ROUGHNESS_ANISOTROPY - var coatRoughnessAnisotropyFromTexture: f32 = textureSample(coatRoughnessAnisotropySampler, coatRoughnessAnisotropySamplerSampler, uniforms.vCoatRoughnessAnisotropyUV + uvOffset).r; + var coatRoughnessAnisotropyFromTexture: f32 = textureSample(coatRoughnessAnisotropySampler, coatRoughnessAnisotropySamplerSampler, fragmentInputs.vCoatRoughnessAnisotropyUV + uvOffset).r; #endif #ifdef COAT_DARKENING - var coatDarkeningFromTexture: vec4f = textureSample(coatDarkeningSampler, coatDarkeningSamplerSampler, uniforms.vCoatDarkeningUV + uvOffset); + var coatDarkeningFromTexture: vec4f = textureSample(coatDarkeningSampler, coatDarkeningSamplerSampler, fragmentInputs.vCoatDarkeningUV + uvOffset); #endif // Initalize coat layer properties from uniforms diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 6357f820f3c..0449c84c80e 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -8,7 +8,6 @@ #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) -#include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) #include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_SAMPLERNAME_,emissionColor) #include(_DEFINENAME_,AMBIENT_OCCLUSION,_VARYINGNAME_,AmbientOcclusion,_SAMPLERNAME_,ambientOcclusion) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx index 36476080e53..22aaa1a5e60 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrNormalMapFragmentFunctions.fx @@ -2,6 +2,10 @@ #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_SAMPLERNAME_,geometryNormal) #endif +#if defined(GEOMETRY_COAT_NORMAL) + #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_SAMPLERNAME_,geometryCoatNormal) +#endif + #if defined(DETAIL) #include(_DEFINENAME_,DETAIL,_VARYINGNAME_,Detail,_SAMPLERNAME_,detail) #endif diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx index 6dbcacbf487..a023a0f1953 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.fragment.fx @@ -47,7 +47,7 @@ #include #include -// #include +#include #include #include From 6f743f0612bd533072ae112e99be39e18cabb7fb Mon Sep 17 00:00:00 2001 From: MiiBond Date: Tue, 5 Aug 2025 08:19:41 -0700 Subject: [PATCH 32/45] Update and rename openPbrUboDeclaration.fx to openpbrUboDeclaration.fx --- .../{openPbrUboDeclaration.fx => openpbrUboDeclaration.fx} | 1 + 1 file changed, 1 insertion(+) rename packages/dev/core/src/ShadersWGSL/ShadersInclude/{openPbrUboDeclaration.fx => openpbrUboDeclaration.fx} (96%) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx similarity index 96% rename from packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx rename to packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx index f06b091c6aa..32b7fe21f81 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openPbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx @@ -81,3 +81,4 @@ uniform ambientOcclusionMatrix: mat4x4f; #include #include + From 101fd4b6e5e9a1ca894b3a90de558b0101d11a60 Mon Sep 17 00:00:00 2001 From: MiiBond Date: Tue, 5 Aug 2025 08:20:46 -0700 Subject: [PATCH 33/45] Update and rename openPbrUboDeclaration.fx to openpbrUboDeclaration.fx --- .../{openPbrUboDeclaration.fx => openpbrUboDeclaration.fx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/dev/core/src/Shaders/ShadersInclude/{openPbrUboDeclaration.fx => openpbrUboDeclaration.fx} (100%) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx similarity index 100% rename from packages/dev/core/src/Shaders/ShadersInclude/openPbrUboDeclaration.fx rename to packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx From 828529ac79427975c15a56e9d3cb716d01ea4ecc Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 5 Aug 2025 12:32:29 -0700 Subject: [PATCH 34/45] Fix default glTF PBR values --- .../core/src/Materials/standardMaterial.ts | 2 +- .../pbrMaterialPropertyGridComponent.tsx | 1480 ++++++++--------- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 7 + 3 files changed, 722 insertions(+), 767 deletions(-) diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 8d61ed126fe..2db2a131591 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -1470,7 +1470,7 @@ export class StandardMaterial extends StandardMaterialBase { ubo.updateFloat("alphaCutOff", this.alphaCutOff); } - BindIBLParameters(scene, defines, ubo, this._reflectionTexture, false, true, true); + BindIBLParameters(scene, defines, ubo, this._reflectionTexture, false, false, true); if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); 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 d96009b325e..32df71c593e 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 { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; +import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial"; import { Constants } from "core/Engines/constants"; import type { PropertyChangedEvent } from "../../../../propertyChangedEvent"; @@ -19,11 +19,10 @@ 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 | OpenPBRMaterial; + material: PBRMaterial; lockObject: LockObject; onSelectionChangedObservable?: Observable; onPropertyChangedObservable?: Observable; @@ -47,16 +46,14 @@ export class PBRMaterialPropertyGridComponent extends React.Component - {material instanceof PBRMaterial && ( - - )} + - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - this.switchAmbientMode(state)} - label="Ambient" - texture={material.ambientTexture} - propertyName="ambientTexture" - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} - /> - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - <> - (material.detailMap.texture = texture)} - onTextureRemoved={() => (material.detailMap.texture = null)} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} - /> - - - - )} - {material instanceof PBRMaterial && material.decalMap && ( + + + + + + + + + this.switchAmbientMode(state)} + label="Ambient" + texture={material.ambientTexture} + propertyName="ambientTexture" + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} + /> + + (material.detailMap.texture = texture)} + onTextureRemoved={() => (material.detailMap.texture = null)} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} + /> + + + {material.decalMap && ( - {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} - /> - )} + (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 && ( - <> - + + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + {material.clearCoat.isEnabled && ( +
+ + + this.forceUpdate()} + propertyName="remapF0OnInterfaceChange" onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - {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.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 && ( + )} - - this.forceUpdate()} + label="Use roughness from main texture" + target={material.clearCoat} + propertyName="useRoughnessFromMainTexture" onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - {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} - /> -
+ + {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 && ( +
+ + + + + (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 && ( +
this.forceUpdate()} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - {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} - /> -
- )} - - + + + (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 && ( +
this.forceUpdate()} + propertyName="linkSheenWithAlbedo" + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + + + (material.sheen.texture = texture)} + onTextureRemoved={() => (material.sheen.texture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} /> - {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.sheen.textureRoughness = texture)} + onTextureRemoved={() => (material.sheen.textureRoughness = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> + + {(material.sheen as any)._useRoughness && ( + )} - + + +
+ )} +
+ + (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} + /> + - + 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.thicknessTexture = texture)} - onTextureRemoved={() => (material.subSurface.thicknessTexture = null)} + label="Refraction Intensity" + texture={material.subSurface.refractionIntensityTexture} + onTextureCreated={(texture) => (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()} + propertyName="linkRefractionWithTransparency" onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> this.forceUpdate()} + propertyName="useAlbedoToTintRefraction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - + )} + + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + {material.subSurface.isDispersionEnabled && ( +
+ this.forceUpdate()} + propertyName="dispersion" + minimum={0} + maximum={5} + step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - + )} + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + {material.subSurface.isTranslucencyEnabled && ( +
+ - - this.forceUpdate()} - onPropertyChangedObservable={this.props.onPropertyChangedObservable} + (material.subSurface.translucencyIntensityTexture = texture)} + onTextureRemoved={() => (material.subSurface.translucencyIntensityTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} /> - {(material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration && ( -
- -
- )} - this.forceUpdate()} + propertyName="diffusionDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} + isLinear={true} /> - {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)} - material={material} - onSelectionChangedObservable={this.props.onSelectionChangedObservable} - onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} - /> - - - - -
- )} - this.forceUpdate()} + propertyName="useAlbedoToTintTranslucency" onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> - {material.subSurface.isDispersionEnabled && ( -
- -
- )} - this.forceUpdate()} + propertyName="translucencyColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} + isLinear={true} /> - {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.subSurface.translucencyColorTexture = texture)} + onTextureRemoved={() => (material.subSurface.translucencyColorTexture = null)} + material={material} + onSelectionChangedObservable={this.props.onSelectionChangedObservable} + onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} + /> +
+ )} + - {material instanceof PBRMaterial && material.bumpTexture && ( + {material.bumpTexture && ( )} - {material instanceof PBRMaterial && material.ambientTexture && ( + {material.ambientTexture && ( )} - {material instanceof PBRMaterial && material.reflectionTexture && ( + {material.reflectionTexture && ( )} - {material instanceof PBRMaterial && material.clearCoat.texture && ( + {material.clearCoat.texture && ( )} - {material instanceof PBRMaterial && material.clearCoat.bumpTexture && ( + {material.clearCoat.bumpTexture && ( )} - {material instanceof PBRMaterial && material.clearCoat.tintTexture && false /* level is not used for the clear coat tint texture */ && ( + {material.clearCoat.tintTexture && false /* level is not used for the clear coat tint texture */ && ( )} - {material instanceof PBRMaterial && material.anisotropy.texture && ( + {material.anisotropy.texture && ( )} - {material instanceof PBRMaterial && material.sheen.texture && ( + {material.sheen.texture && ( )} - {material instanceof PBRMaterial && material.subSurface.thicknessTexture && ( + {material.subSurface.thicknessTexture && ( )} - {material instanceof PBRMaterial && material.subSurface.refractionTexture && ( + {material.subSurface.refractionTexture && ( )} - {material instanceof PBRMaterial && material.detailMap.isEnabled && ( + {material.detailMap.isEnabled && ( <> - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} - {material instanceof PBRMaterial && ( - - )} + + + - {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} - /> - - )} + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> + this.forceUpdate()} + onPropertyChangedObservable={this.props.onPropertyChangedObservable} + /> diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index c9d278bda6c..9d07cf7a397 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -2272,6 +2272,13 @@ export class GLTFLoader implements IGLTFLoader { (babylonMaterial as PBRMaterial).useSpecularOverAlpha = !this._parent.transparencyAsCoverage; } babylonMaterial.transparencyMode = PBRMaterialClass.PBRMATERIAL_OPAQUE; + if (this.parent.useOpenPBR) { + (babylonMaterial as OpenPBRMaterial).baseMetalness = 1.0; + (babylonMaterial as OpenPBRMaterial).specularRoughness = 1.0; + } else { + (babylonMaterial as PBRMaterial).metallic = 1.0; + (babylonMaterial as PBRMaterial).roughness = 1.0; + } return babylonMaterial; } From aece67e91cb380ef2bb0a63db69c3fb6468793ca Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 5 Aug 2025 15:31:21 -0700 Subject: [PATCH 35/45] Fixes for vis tests --- .../src/Materials/materialHelper.functions.ts | 6 +- .../core/src/Materials/standardMaterial.ts | 16 ++++- .../Extensions/KHR_materials_transmission.ts | 60 +++++++++---------- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index 56201265756..ae98e59411e 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -741,6 +741,7 @@ export function PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, define * @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 + * @returns true if the defines were updated */ export function PrepareDefinesForIBL( scene: Scene, @@ -749,10 +750,10 @@ export function PrepareDefinesForIBL( realTimeFiltering: boolean = false, realTimeFilteringQuality: number = Constants.TEXTURE_FILTERING_QUALITY_LOW, forceSHInVertex: boolean = false -) { +): boolean { if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) { if (!reflectionTexture.isReadyOrNotBlocking()) { - return; + return false; } defines.REFLECTION = true; defines.GAMMAREFLECTION = reflectionTexture.gammaSpace; @@ -864,6 +865,7 @@ export function PrepareDefinesForIBL( defines.RGBDREFLECTION = false; defines.LINEARSPECULARREFLECTION = false; } + return true; } /** diff --git a/packages/dev/core/src/Materials/standardMaterial.ts b/packages/dev/core/src/Materials/standardMaterial.ts index 2db2a131591..b9edecfc53f 100644 --- a/packages/dev/core/src/Materials/standardMaterial.ts +++ b/packages/dev/core/src/Materials/standardMaterial.ts @@ -827,9 +827,16 @@ export class StandardMaterial extends StandardMaterialBase { } else { defines.OPACITY = false; } - defines.ROUGHNESS = this._roughness > 0; - defines.REFLECTIONOVERALPHA = this._useReflectionOverAlpha; - PrepareDefinesForIBL(scene, this._reflectionTexture, defines); + if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) { + defines.ROUGHNESS = this._roughness > 0; + defines.REFLECTIONOVERALPHA = this._useReflectionOverAlpha; + } else { + defines.ROUGHNESS = false; + defines.REFLECTIONOVERALPHA = false; + } + if (!PrepareDefinesForIBL(scene, this._reflectionTexture, defines)) { + return false; + } if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { if (!this._emissiveTexture.isReadyOrNotBlocking()) { @@ -1471,6 +1478,9 @@ export class StandardMaterial extends StandardMaterialBase { } BindIBLParameters(scene, defines, ubo, this._reflectionTexture, false, false, true); + if (!this._reflectionTexture || !StandardMaterial.ReflectionTextureEnabled) { + ubo.updateFloat2("vReflectionInfos", 0.0, this.roughness); + } if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); 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 c0022868174..e66b068e19d 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 @@ -397,11 +397,14 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { if (!(babylonMaterial instanceof PBRMaterialClass)) { throw new Error(`${context}: Material type not supported`); } + if (useOpenPBR) { + return Promise.resolve(); + } let transmissionWeight = 0.0; let transmissionWeightTexture: Nullable = null; - const promises = new Array>(); + let texturePromise = new Promise>((resolve) => resolve(null)); if (extension.transmissionFactor !== undefined) { transmissionWeight = extension.transmissionFactor; } else { @@ -410,43 +413,40 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension { if (extension.transmissionTexture) { (extension.transmissionTexture as ITextureInfo).nonColorData = true; // eslint-disable-next-line github/no-then - promises.push( - this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, (texture: BaseTexture) => { - texture.name = `${babylonMaterial.name} (Transmission)`; - transmissionWeightTexture = texture; - }) - ); + texturePromise = 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; + const pbrMaterial = babylonMaterial as PBRMaterial; - // Enables "refraction" texture which represents transmitted light. - pbrMaterial.subSurface.isRefractionEnabled = transmissionWeight !== 0; + // 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; + // 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; + // Albedo colour will tint transmission. + pbrMaterial.subSurface.useAlbedoToTintRefraction = true; - pbrMaterial.subSurface.refractionIntensity = transmissionWeight; + 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(); - } + 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.minimumThickness = 0.0; + pbrMaterial.subSurface.maximumThickness = 0.0; + + // eslint-disable-next-line github/no-then + return texturePromise.then(() => { pbrMaterial.subSurface.refractionIntensityTexture = transmissionWeightTexture; pbrMaterial.subSurface.useGltfStyleTextures = true; }); From a21bfe7b86a6e6ec5c6f3f1277b61e63f61cf6cc Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Tue, 5 Aug 2025 16:14:14 -0700 Subject: [PATCH 36/45] Fix specular extension loading --- .../core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx | 2 +- .../src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx | 2 +- .../loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx index d6d18b2ef8e..a8eff6df01f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrBaseLayerData.fx @@ -44,7 +44,7 @@ float alpha = 1.0; #ifdef SPECULAR_COLOR vec4 specularColorFromTexture = texture2D(specularColorSampler, vSpecularColorUV + uvOffset); #ifdef SPECULAR_COLOR_GAMMA - specularColorFromTexture = toLinearSpace(specularColorFromTexture.rgb); + specularColorFromTexture.rgb = toLinearSpace(specularColorFromTexture.rgb); #endif #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx index ed78ab57fbc..c94d77c43f4 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.fx @@ -44,7 +44,7 @@ var alpha: f32 = 1.0; #ifdef SPECULAR_COLOR var specularColorFromTexture: vec4f = textureSample(specularColorSampler, specularColorSamplerSampler, fragmentInputs.vSpecularColorUV + uvOffset); #ifdef SPECULAR_COLOR_GAMMA - specularColorFromTexture = toLinearSpace(specularColorFromTexture.rgb); + specularColorFromTexture.rgb = toLinearSpace(specularColorFromTexture.rgb); #endif #endif 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 61d705cb697..9cc95e649e5 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 @@ -98,6 +98,7 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { } const promises = new Array>(); + promises.push(Promise.resolve()); if (useOpenPBR) { if (properties.specularFactor !== undefined) { @@ -151,7 +152,7 @@ export class KHR_materials_specular implements IGLTFLoaderExtension { promises.push( this._loader.loadTextureInfoAsync(`${context}/specularColorTexture`, properties.specularColorTexture, (texture) => { texture.name = `${babylonMaterial.name} (Specular Color)`; - (babylonMaterial as PBRMaterial).reflectionTexture = texture; + (babylonMaterial as PBRMaterial).reflectanceTexture = texture; }) ); } From 9bf40773fdb80ef5515fd9985e48fa6d55df3c62 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 6 Aug 2025 12:44:02 -0700 Subject: [PATCH 37/45] Fix for mixin constructor names --- packages/dev/core/src/Materials/PBR/openPbrMaterial.ts | 9 ++++++--- packages/dev/core/src/Materials/imageProcessing.ts | 4 ++-- .../Materials/imageProcessingConfiguration.defines.ts | 4 ++-- packages/dev/core/src/Materials/uv.defines.ts | 4 ++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index d28e62031e1..5464a06e17e 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -207,8 +207,6 @@ class OpenPBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {} * @internal */ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRMaterialDefinesBase) { - public PBR = true; - public NUM_SAMPLES = "0"; public REALTIME_FILTERING = false; public IBL_CDF_FILTERING = false; @@ -386,7 +384,6 @@ export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRM public override reset(): void { super.reset(); this.ALPHATESTVALUE = "0.5"; - this.PBR = true; this.NORMALXYSCALE = true; } } @@ -616,6 +613,12 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _coatIor: Property = new Property("coat_ior", 1.5, "vCoatIor", 1, 0); + /** + * Specifies whether the coat roughness is taken from the + * same texture as the coat_weight. + */ + public useCoatRoughnessFromWeightTexture: boolean = false; + /** * Defines the normal of the material's geometry. * See OpenPBR's specs for geometry_normal diff --git a/packages/dev/core/src/Materials/imageProcessing.ts b/packages/dev/core/src/Materials/imageProcessing.ts index ab9d8f5da2d..f1dd7c39d78 100644 --- a/packages/dev/core/src/Materials/imageProcessing.ts +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -10,13 +10,13 @@ import type { ColorCurves } from "../Materials/colorCurves"; // export type { Observer } from "../Misc/observable"; // export type { ColorCurves } from "./colorCurves"; -type Constructor = new (...args: any[]) => T; +type ImageProcessingMixinConstructor = new (...args: any[]) => T; /** * Mixin to add Image processing defines to your material defines * @internal */ -export function ImageProcessingMixin(base: Tbase) { +export function ImageProcessingMixin(base: Tbase) { return class extends base { /** * Constructor for the ImageProcessingMixin. diff --git a/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts b/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts index de659b50f28..7ddc3b16bbf 100644 --- a/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts +++ b/packages/dev/core/src/Materials/imageProcessingConfiguration.defines.ts @@ -22,13 +22,13 @@ export interface IImageProcessingConfigurationDefines { SKIPFINALCOLORCLAMP: boolean; } -type Constructor = new (...args: any[]) => T; +type ImageProcessingDefinesMixinConstructor = new (...args: any[]) => T; /** * Mixin to add Image processing defines to your material defines * @internal */ -export function ImageProcessingDefinesMixin(base: Tbase) { +export function ImageProcessingDefinesMixin(base: Tbase) { return class extends base implements IImageProcessingConfigurationDefines { // Implement all members of IImageProcessingConfigurationDefines here public IMAGEPROCESSING = false; diff --git a/packages/dev/core/src/Materials/uv.defines.ts b/packages/dev/core/src/Materials/uv.defines.ts index 12eec96845c..1928a17f486 100644 --- a/packages/dev/core/src/Materials/uv.defines.ts +++ b/packages/dev/core/src/Materials/uv.defines.ts @@ -1,10 +1,10 @@ -type Constructor = new (...args: any[]) => T; +type UVDefinesMixinConstructor = new (...args: any[]) => T; /** * Mixin to add UV defines to your material defines * @internal */ -export function UVDefinesMixin(base: Tbase) { +export function UVDefinesMixin(base: Tbase) { return class extends base { public MAINUV1 = false; public MAINUV2 = false; From bff96daedc83d26ed494b96b7e25e6c399ff7461 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 6 Aug 2025 12:45:07 -0700 Subject: [PATCH 38/45] Adding support to export GLB with OpenPBR --- .../2.0/Extensions/KHR_materials_clearcoat.ts | 51 ++++++++++++ .../serializers/src/glTF/2.0/glTFExporter.ts | 3 + .../src/glTF/2.0/glTFMaterialExporter.ts | 83 +++++++++++++++---- 3 files changed, 121 insertions(+), 16 deletions(-) diff --git a/packages/dev/serializers/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts b/packages/dev/serializers/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts index 4aad4002efb..f81e9f6cb1d 100644 --- a/packages/dev/serializers/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts +++ b/packages/dev/serializers/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts @@ -6,6 +6,7 @@ import { PBRBaseMaterial } from "core/Materials/PBR/pbrBaseMaterial"; import type { BaseTexture } from "core/Materials/Textures/baseTexture"; import { Tools } from "core/Misc/tools"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; const NAME = "KHR_materials_clearcoat"; @@ -53,6 +54,19 @@ export class KHR_materials_clearcoat implements IGLTFExporterExtensionV2 { } return additionalTextures; } + } else if (babylonMaterial instanceof OpenPBRMaterial) { + if (babylonMaterial.coatWeight > 0) { + if (babylonMaterial.coatWeightTexture) { + additionalTextures.push(babylonMaterial.coatWeightTexture); + } + if (babylonMaterial.geometryCoatNormalTexture) { + additionalTextures.push(babylonMaterial.geometryCoatNormalTexture); + } + if (babylonMaterial.coatRoughnessTexture) { + additionalTextures.push(babylonMaterial.coatRoughnessTexture); + } + return additionalTextures; + } } return []; @@ -101,6 +115,43 @@ export class KHR_materials_clearcoat implements IGLTFExporterExtensionV2 { this._exporter._materialNeedsUVsSet.add(babylonMaterial); } + node.extensions[NAME] = clearCoatInfo; + } else if (babylonMaterial instanceof OpenPBRMaterial) { + if (babylonMaterial.coatWeight == 0.0) { + resolve(node); + return; + } + + this._wasUsed = true; + + node.extensions = node.extensions || {}; + + const clearCoatTextureInfo = this._exporter._materialExporter.getTextureInfo(babylonMaterial.coatWeightTexture); + let clearCoatTextureRoughnessInfo; + if (babylonMaterial.useCoatRoughnessFromWeightTexture) { + clearCoatTextureRoughnessInfo = this._exporter._materialExporter.getTextureInfo(babylonMaterial.coatWeightTexture); + } else { + clearCoatTextureRoughnessInfo = this._exporter._materialExporter.getTextureInfo(babylonMaterial.coatRoughnessTexture); + } + + if (babylonMaterial.coatColorTexture) { + Tools.Warn(`Clear Color tint is not supported for glTF export. Ignoring for: ${babylonMaterial.name}`); + } + + const clearCoatNormalTextureInfo = this._exporter._materialExporter.getTextureInfo(babylonMaterial.geometryCoatNormalTexture); + + const clearCoatInfo: IKHRMaterialsClearcoat = { + clearcoatFactor: babylonMaterial.coatWeight, + clearcoatTexture: clearCoatTextureInfo ?? undefined, + clearcoatRoughnessFactor: babylonMaterial.coatRoughness, + clearcoatRoughnessTexture: clearCoatTextureRoughnessInfo ?? undefined, + clearcoatNormalTexture: clearCoatNormalTextureInfo ?? undefined, + }; + + if (clearCoatInfo.clearcoatTexture !== null || clearCoatInfo.clearcoatRoughnessTexture !== null || clearCoatInfo.clearcoatRoughnessTexture !== null) { + this._exporter._materialNeedsUVsSet.add(babylonMaterial); + } + node.extensions[NAME] = clearCoatInfo; } resolve(node); diff --git a/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts b/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts index f35f7202b7d..1374656c22e 100644 --- a/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts +++ b/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts @@ -80,6 +80,7 @@ import { Color3, Color4 } from "core/Maths/math.color"; import { TargetCamera } from "core/Cameras/targetCamera"; import { Epsilon } from "core/Maths/math.constants"; import { DataWriter } from "./dataWriter"; +import { OpenPBRMaterial } from "core/Materials"; class ExporterState { // Babylon indices array, start, count, offset, flip -> glTF accessor index @@ -1411,6 +1412,8 @@ export class GLTFExporter { materialIndex = await this._materialExporter.exportPBRMaterialAsync(babylonMaterial, hasUVs); } else if (babylonMaterial instanceof StandardMaterial) { materialIndex = await this._materialExporter.exportStandardMaterialAsync(babylonMaterial, hasUVs); + } else if (babylonMaterial instanceof OpenPBRMaterial) { + materialIndex = await this._materialExporter.exportOpenPBRMaterialAsync(babylonMaterial, hasUVs); } else { Logger.Warn(`Unsupported material '${babylonMaterial.name}' with type ${babylonMaterial.getClassName()}`); return; diff --git a/packages/dev/serializers/src/glTF/2.0/glTFMaterialExporter.ts b/packages/dev/serializers/src/glTF/2.0/glTFMaterialExporter.ts index 00788b831d4..88d433846ac 100644 --- a/packages/dev/serializers/src/glTF/2.0/glTFMaterialExporter.ts +++ b/packages/dev/serializers/src/glTF/2.0/glTFMaterialExporter.ts @@ -22,8 +22,9 @@ import { DumpTools } from "core/Misc/dumpTools"; import type { Material } from "core/Materials/material"; import type { StandardMaterial } from "core/Materials/standardMaterial"; -import type { PBRBaseMaterial } from "core/Materials/PBR/pbrBaseMaterial"; +import { PBRBaseMaterial } from "core/Materials/PBR/pbrBaseMaterial"; import { SpecularPowerToRoughness } from "core/Helpers/materialConversionHelper"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; const Epsilon = 1e-6; const DielectricSpecular = new Color3(0.04, 0.04, 0.04); @@ -524,26 +525,35 @@ export class GLTFMaterialExporter { /** * Convert a PBRMaterial (Metallic/Roughness) to Metallic Roughness factors + * @param baseColor Base color of the material + * @param metallic Metallic factor of the material + * @param roughness Roughness factor of the material + * @param albedoTexture Albedo texture of the material + * @param metallicRoughnessTexture Metallic roughness texture of the material * @param babylonPBRMaterial BJS PBR Metallic Roughness Material * @param glTFPbrMetallicRoughness glTF PBR Metallic Roughness interface * @param hasUVs specifies if texture coordinates are present on the submesh to determine if textures should be applied * @returns glTF PBR Metallic Roughness factors */ private async _convertMetalRoughFactorsToMetallicRoughnessAsync( - babylonPBRMaterial: PBRBaseMaterial, + baseColor: Color3, + metallic: Nullable, + roughness: Nullable, + albedoTexture: Nullable, + metallicRoughnessTexture: Nullable, + babylonPBRMaterial: PBRBaseMaterial | OpenPBRMaterial, glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness, hasUVs: boolean ): Promise { const promises: Promise[] = []; const metallicRoughness: IPBRMetallicRoughness = { - baseColor: babylonPBRMaterial._albedoColor, - metallic: babylonPBRMaterial._metallic, - roughness: babylonPBRMaterial._roughness, + baseColor: baseColor, + metallic: metallic, + roughness: roughness, }; if (hasUVs) { - const albedoTexture = babylonPBRMaterial._albedoTexture; if (albedoTexture) { promises.push( this.exportTextureAsync(albedoTexture).then((glTFTexture) => { @@ -553,10 +563,9 @@ export class GLTFMaterialExporter { }) ); } - const metallicTexture = babylonPBRMaterial._metallicTexture; - if (metallicTexture) { + if (metallicRoughnessTexture) { promises.push( - this.exportTextureAsync(metallicTexture).then((glTFTexture) => { + this.exportTextureAsync(metallicRoughnessTexture).then((glTFTexture) => { if (glTFTexture) { glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture; } @@ -741,7 +750,16 @@ export class GLTFMaterialExporter { } const metallicRoughness = useMetallicRoughness - ? await this._convertMetalRoughFactorsToMetallicRoughnessAsync(babylonPBRMaterial, glTFPbrMetallicRoughness, hasUVs) + ? await this._convertMetalRoughFactorsToMetallicRoughnessAsync( + babylonPBRMaterial._albedoColor, + babylonPBRMaterial._metallic, + babylonPBRMaterial._roughness, + babylonPBRMaterial._albedoTexture, + babylonPBRMaterial._metallicTexture, + babylonPBRMaterial, + glTFPbrMetallicRoughness, + hasUVs + ) : await this._convertSpecGlossFactorsToMetallicRoughnessAsync(babylonPBRMaterial, glTFPbrMetallicRoughness, hasUVs); await this._setMetallicRoughnessPbrMaterialAsync(metallicRoughness, babylonPBRMaterial, glTFMaterial, glTFPbrMetallicRoughness, hasUVs); @@ -754,7 +772,7 @@ export class GLTFMaterialExporter { private async _setMetallicRoughnessPbrMaterialAsync( metallicRoughness: IPBRMetallicRoughness, - babylonPBRMaterial: PBRBaseMaterial, + babylonPBRMaterial: PBRBaseMaterial | OpenPBRMaterial, glTFMaterial: IMaterial, glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness, hasUVs: boolean @@ -782,7 +800,7 @@ export class GLTFMaterialExporter { if (hasUVs) { const promises: Promise[] = []; - const bumpTexture = babylonPBRMaterial._bumpTexture; + const bumpTexture = babylonPBRMaterial instanceof PBRBaseMaterial ? babylonPBRMaterial._bumpTexture : babylonPBRMaterial.geometryNormalTexture; if (bumpTexture) { promises.push( this.exportTextureAsync(bumpTexture).then((glTFTexture) => { @@ -796,7 +814,7 @@ export class GLTFMaterialExporter { ); } - const ambientTexture = babylonPBRMaterial._ambientTexture; + const ambientTexture = babylonPBRMaterial instanceof PBRBaseMaterial ? babylonPBRMaterial._ambientTexture : babylonPBRMaterial.ambientOcclusionTexture; if (ambientTexture) { promises.push( this.exportTextureAsync(ambientTexture).then((glTFTexture) => { @@ -808,7 +826,8 @@ export class GLTFMaterialExporter { }; glTFMaterial.occlusionTexture = occlusionTexture; - const ambientTextureStrength = babylonPBRMaterial._ambientTextureStrength; + const ambientTextureStrength = + babylonPBRMaterial instanceof PBRBaseMaterial ? babylonPBRMaterial._ambientTextureStrength : babylonPBRMaterial.ambientOcclusionTexture.level; if (ambientTextureStrength) { occlusionTexture.strength = ambientTextureStrength; } @@ -817,7 +836,7 @@ export class GLTFMaterialExporter { ); } - const emissiveTexture = babylonPBRMaterial._emissiveTexture; + const emissiveTexture = babylonPBRMaterial instanceof PBRBaseMaterial ? babylonPBRMaterial._emissiveTexture : babylonPBRMaterial.emissionColorTexture; if (emissiveTexture) { promises.push( this.exportTextureAsync(emissiveTexture).then((glTFTexture) => { @@ -834,7 +853,7 @@ export class GLTFMaterialExporter { } } - const emissiveColor = babylonPBRMaterial._emissiveColor; + const emissiveColor = babylonPBRMaterial instanceof PBRBaseMaterial ? babylonPBRMaterial._emissiveColor : babylonPBRMaterial.emissionColor; if (!emissiveColor.equalsWithEpsilon(Black, Epsilon)) { glTFMaterial.emissiveFactor = emissiveColor.asArray(); } @@ -842,6 +861,38 @@ export class GLTFMaterialExporter { glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness; } + public async exportOpenPBRMaterialAsync(babylonOpenPBRMaterial: OpenPBRMaterial, hasUVs: boolean): Promise { + const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {}; + + const glTFMaterial: IMaterial = { + name: babylonOpenPBRMaterial.name, + }; + + const albedoColor = babylonOpenPBRMaterial.baseColor; + const alpha = babylonOpenPBRMaterial.geometryOpacity; + if (albedoColor) { + glTFPbrMetallicRoughness.baseColorFactor = [albedoColor.r, albedoColor.g, albedoColor.b, alpha]; + } + + const metallicRoughness = await this._convertMetalRoughFactorsToMetallicRoughnessAsync( + babylonOpenPBRMaterial.baseColor, + babylonOpenPBRMaterial.baseMetalness, + babylonOpenPBRMaterial.specularRoughness, + babylonOpenPBRMaterial.baseColorTexture, + babylonOpenPBRMaterial.baseMetalRoughTexture, + babylonOpenPBRMaterial, + glTFPbrMetallicRoughness, + hasUVs + ); + + await this._setMetallicRoughnessPbrMaterialAsync(metallicRoughness, babylonOpenPBRMaterial, glTFMaterial, glTFPbrMetallicRoughness, hasUVs); + await this._finishMaterialAsync(glTFMaterial, babylonOpenPBRMaterial); + + const materials = this._exporter._materials; + materials.push(glTFMaterial); + return materials.length - 1; + } + public async exportTextureAsync(babylonTexture: BaseTexture): Promise> { let textureInfo = this._textureMap.get(babylonTexture); if (textureInfo) { From c1c5f187bbe79e34599325e0385623a46246b7c4 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Wed, 6 Aug 2025 12:49:44 -0700 Subject: [PATCH 39/45] Add vis test for OpenPBR normal mapping --- .../ShadersInclude/openpbrNormalMapFragment.fx | 2 +- ...nPBR-IBL-Normal-and-Coat-Normal-Mapping.png | Bin 0 -> 127993 bytes .../tools/tests/test/visualization/config.json | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Normal-and-Coat-Normal-Mapping.png diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx index 6083fc4ae51..3738d278e63 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrNormalMapFragment.fx @@ -48,7 +48,7 @@ #endif #ifdef GEOMETRY_COAT_NORMAL - coatNormalW = perturbNormal(TBN, texture2D(geometryNormalSampler, vGeometryNormalUV + uvOffset).xyz, vGeometryNormalInfos.y); + coatNormalW = perturbNormal(TBN, texture2D(geometryCoatNormalSampler, vGeometryCoatNormalUV + uvOffset).xyz, vGeometryCoatNormalInfos.y); #endif #ifdef GEOMETRY_NORMAL diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Normal-and-Coat-Normal-Mapping.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Normal-and-Coat-Normal-Mapping.png new file mode 100644 index 0000000000000000000000000000000000000000..bc6909c54605854bb535a92ba31f23956a4dd3a2 GIT binary patch literal 127993 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 Date: Wed, 6 Aug 2025 15:25:23 -0700 Subject: [PATCH 40/45] OpenPBRMaterial export to glTF for diffuse roughness --- .../dev/core/src/Materials/imageProcessing.ts | 4 -- .../tabs/propertyGridTabComponent.tsx | 4 +- .../EXT_materials_diffuse_roughness.ts | 49 +++++++++++++------ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/dev/core/src/Materials/imageProcessing.ts b/packages/dev/core/src/Materials/imageProcessing.ts index f1dd7c39d78..2bcba2bd245 100644 --- a/packages/dev/core/src/Materials/imageProcessing.ts +++ b/packages/dev/core/src/Materials/imageProcessing.ts @@ -6,10 +6,6 @@ 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 ImageProcessingMixinConstructor = new (...args: any[]) => T; /** diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index 0235400d2f6..a2deb3ff06b 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx @@ -398,7 +398,9 @@ export class PropertyGridTabComponent extends PaneComponent { onPropertyChangedObservable={this.props.onPropertyChangedObservable} /> ); - } else if (className === "OpenPBRMaterial") { + } + + if (className === "OpenPBRMaterial") { const material = entity as OpenPBRMaterial; return ( { return new Promise((resolve) => { + let diffuseRoughnessFactor: Nullable = null; + let diffuseRoughnessTexture: Nullable = null; if (babylonMaterial instanceof PBRBaseMaterial) { - if (!babylonMaterial._baseDiffuseRoughness) { - resolve(node); - return; - } - - this._wasUsed = true; + diffuseRoughnessFactor = babylonMaterial._baseDiffuseRoughness; + diffuseRoughnessTexture = babylonMaterial._baseDiffuseRoughnessTexture; + } else if (babylonMaterial instanceof OpenPBRMaterial) { + diffuseRoughnessFactor = babylonMaterial.baseDiffuseRoughness; + diffuseRoughnessTexture = babylonMaterial.baseDiffuseRoughnessTexture; + } + if (!diffuseRoughnessFactor) { + resolve(node); + return; + } - node.extensions = node.extensions || {}; + this._wasUsed = true; - const diffuseRoughnessTextureInfo = this._exporter._materialExporter.getTextureInfo(babylonMaterial._baseDiffuseRoughnessTexture); + node.extensions = node.extensions || {}; - const diffuseRoughnessInfo: IEXTMaterialsDiffuseRoughness = { - diffuseRoughnessFactor: babylonMaterial._baseDiffuseRoughness, - diffuseRoughnessTexture: diffuseRoughnessTextureInfo ?? undefined, - }; + const diffuseRoughnessTextureInfo = this._exporter._materialExporter.getTextureInfo(diffuseRoughnessTexture); - if (diffuseRoughnessInfo.diffuseRoughnessTexture !== null) { - this._exporter._materialNeedsUVsSet.add(babylonMaterial); - } + const diffuseRoughnessInfo: IEXTMaterialsDiffuseRoughness = { + diffuseRoughnessFactor: diffuseRoughnessFactor, + diffuseRoughnessTexture: diffuseRoughnessTextureInfo ?? undefined, + }; - node.extensions[NAME] = diffuseRoughnessInfo; + if (diffuseRoughnessInfo.diffuseRoughnessTexture !== null) { + this._exporter._materialNeedsUVsSet.add(babylonMaterial); } + + node.extensions[NAME] = diffuseRoughnessInfo; + resolve(node); }); } From 3cddebc151752fd4ac9a817207c8325a49b2dde8 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Thu, 7 Aug 2025 12:44:41 -0700 Subject: [PATCH 41/45] Add coat_darkening to OpenPBR --- .../core/src/Materials/PBR/openPbrMaterial.ts | 22 ++++++++++ .../ShadersInclude/openpbrCoatLayerData.fx | 2 +- .../ShadersInclude/openpbrDirectLighting.fx | 25 ++++++++++- .../openpbrEnvironmentLighting.fx | 22 +++++++++- .../openpbrFragmentDeclaration.fx | 5 +++ .../openpbrFragmentSamplersDeclaration.fx | 2 + .../ShadersInclude/openpbrUboDeclaration.fx | 3 ++ .../openpbrVertexDeclaration.fx | 40 +++++++++++++++--- .../dev/core/src/Shaders/openpbr.vertex.fx | 4 ++ .../ShadersInclude/openpbrCoatLayerData.fx | 2 +- .../ShadersInclude/openpbrDirectLighting.fx | 25 ++++++++++- .../openpbrEnvironmentLighting.fx | 20 ++++++++- .../openpbrFragmentSamplersDeclaration.fx | 2 + .../ShadersInclude/openpbrUboDeclaration.fx | 3 ++ .../core/src/ShadersWGSL/openpbr.vertex.fx | 4 ++ ...OpenPBR-Analytic-Lights-Coat-Darkening.png | Bin 0 -> 38084 bytes .../OpenPBR-IBL-Coat-Darkening.png | Bin 0 -> 105683 bytes .../tests/test/visualization/config.json | 10 +++++ 18 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Coat-Darkening.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Coat-Darkening.png diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 5464a06e17e..58c038f29a4 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -613,6 +613,28 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { // eslint-disable-next-line @typescript-eslint/no-unused-vars private _coatIor: Property = new Property("coat_ior", 1.5, "vCoatIor", 1, 0); + /** + * Defines the amount that interreflections within the coat allow the underlying surface + * to be darkened. A value of 1.0 means that the physically correct amount of darkening + * is applied, while a value of 0.0 means that no darkening is applied. + * See OpenPBR's specs for coat_darkening + */ + public coatDarkening: number; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatDarkening") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatDarkening: Property = new Property("coat_darkening", 0.0, "vCoatDarkening", 1, 0); + + /** + * Defines the amount that interreflections within the coat allow the underlying surface + * to be darkened. A value of 1.0 means that the physically correct amount of darkening + * is applied, while a value of 0.0 means that no darkening is applied. + * See OpenPBR's specs for coat_darkening + */ + public coatDarkeningTexture: Nullable; + @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatDarkeningTexture") + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private _coatDarkeningTexture: Sampler = new Sampler("coat_darkening", "coatDarkening", "COAT_DARKENING"); + /** * Specifies whether the coat roughness is taken from the * same texture as the coat_weight. diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx index 081db0426d4..114b84a29db 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrCoatLayerData.fx @@ -35,7 +35,7 @@ coat_weight = vCoatWeight; coat_roughness = vCoatRoughness; // coat_roughness_anisotropy = vCoatRoughnessAnisotropy; coat_ior = vCoatIor; -// coat_darkening = vCoatDarkening; +coat_darkening = vCoatDarkening; // Apply texture values to coat layer properties #ifdef COAT_WEIGHT diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx index ea88a610596..4fa285fc1eb 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrDirectLighting.fx @@ -82,12 +82,35 @@ } #endif + vec3 coatAbsorption = vec3(1.0); + if (coat_weight > 0.0) { + // __________ Coat Darkening _____________ + float cosTheta_view = max(preInfoCoat{X}.NdotV, 0.001); + float cosTheta_light = max(preInfoCoat{X}.NdotL, 0.001); + + // Fresnel reflectance for view direction + float fresnel_view = coatReflectance.F0 + (1.0 - coatReflectance.F0) * pow(1.0 - cosTheta_view, 5.0); + + // Fresnel reflectance for light direction + float fresnel_light = coatReflectance.F0 + (1.0 - coatReflectance.F0) * pow(1.0 - cosTheta_light, 5.0); + + // Average reflectance for the round trip (light in, view out) + float averageReflectance = (fresnel_view + fresnel_light) * 0.5; + + // Calculate transmission through multiple internal reflections + // This uses the geometric series for infinite reflections: + // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² + float effectiveReflectance = averageReflectance * coat_weight; + float transmission = (1.0 - effectiveReflectance) / (1.0 + effectiveReflectance); + coatAbsorption = coat_color * mix(1.0, transmission, coat_darkening); + } + slab_diffuse *= base_color.rgb; vec3 material_opaque_base = mix(slab_diffuse, slab_subsurface, subsurface_weight); vec3 material_dielectric_base = mix(material_opaque_base, slab_translucent, transmission_weight); vec3 material_dielectric_gloss = layer(material_dielectric_base, slab_glossy, specularFresnel, vec3(1.0), specular_color); vec3 material_base_substrate = mix(material_dielectric_gloss, slab_metal, base_metalness); - vec3 material_coated_base = layer(material_base_substrate, slab_coat, coatFresnel, coat_color, vec3(1.0)); + vec3 material_coated_base = layer(material_base_substrate, slab_coat, coatFresnel, coatAbsorption, vec3(1.0)); material_surface_direct += mix(material_coated_base, slab_fuzz, fuzz_weight); } #endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx index 20ac47f68ff..93355c5585f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx @@ -104,8 +104,28 @@ slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * vLightingIntensity.z; // _____________________________ Coat Layer IBL _____________________________ + // We will use this absorption value to darken the underlying layers. It includes both the + // abosorption of the coat layer and the darkening due to internal reflections. + vec3 coatAbsorption = vec3(1.0); if (coat_weight > 0.0) { slab_coat_ibl = coatEnvironmentLight * vLightingIntensity.z; + + // __________ Coat Darkening _____________ + // Hemisphere-averaged Fresnel (empirical approximation) + float hemisphere_avg_fresnel = coatReflectance.F0 + 0.5 * (1.0 - coatReflectance.F0); + float averageReflectance = (coatIblFresnel + hemisphere_avg_fresnel) * 0.5; + + // Account for roughness - rougher surfaces have more diffuse internal reflections + // This reduces the darkening effect as roughness increases + float roughnessFactor = 1.0 - coat_roughness * 0.5; + averageReflectance *= roughnessFactor; + + // Calculate transmission through multiple internal reflections + // This uses the geometric series for infinite reflections: + // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² + float effectiveReflectance = averageReflectance * coat_weight; + float transmission = (1.0 - effectiveReflectance) / (1.0 + effectiveReflectance); + coatAbsorption = coat_color * mix(1.0, transmission, coat_darkening); } // TEMP @@ -121,7 +141,7 @@ vec3 material_dielectric_base_ibl = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); vec3 material_dielectric_gloss_ibl = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3(1.0), specular_color); vec3 material_base_substrate_ibl = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); - vec3 material_coated_base_ibl = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3(1.0)); + vec3 material_coated_base_ibl = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coatAbsorption, vec3(1.0)); material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); #endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx index 6415f95ce4b..f626698a83c 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentDeclaration.fx @@ -9,6 +9,7 @@ uniform float vCoatWeight; uniform vec3 vCoatColor; uniform float vCoatRoughness; uniform float vCoatIor; +uniform float vCoatDarkening; uniform vec3 vEmissionColor; // CUSTOM CONTROLS @@ -57,6 +58,10 @@ uniform vec2 vBaseMetalRoughInfos; uniform vec2 vCoatWeightInfos; #endif +#ifdef COAT_DARKENING +uniform vec2 vCoatDarkeningInfos; +#endif + // Refraction Reflection #if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(SS_REFRACTION) || defined(PREPASS) uniform mat4 view; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 818262b6cac..452d2177d53 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -7,6 +7,8 @@ #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_SAMPLERNAME_,coatWeight) #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) +// #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy,_SAMPLERNAME_,coatRoughnessAnisotropy) +#include (_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening,_SAMPLERNAME_,coatDarkening) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) #include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_SAMPLERNAME_,emissionColor) diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx index 1324c6c1c15..fff485abbbd 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrUboDeclaration.fx @@ -69,6 +69,7 @@ uniform Material { vec3 vCoatColor; float vCoatRoughness; float vCoatIor; + float vCoatDarkening; vec3 vEmissionColor; vec2 vBaseWeightInfos; @@ -89,6 +90,8 @@ uniform Material { mat4 coatColorMatrix; vec2 vCoatRoughnessInfos; mat4 coatRoughnessMatrix; + vec2 vCoatDarkeningInfos; + mat4 coatDarkeningMatrix; vec2 vGeometryNormalInfos; mat4 geometryNormalMatrix; vec2 vGeometryCoatNormalInfos; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx index 3a39d06bd5c..a9a6e8da339 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrVertexDeclaration.fx @@ -21,11 +21,6 @@ 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; @@ -56,6 +51,36 @@ uniform vec2 vSpecularColorInfos; uniform mat4 specularColorMatrix; #endif +#ifdef COAT_WEIGHT +uniform vec2 vCoatWeightInfos; +uniform mat4 coatWeightMatrix; +#endif + +#ifdef COAT_COLOR +uniform vec2 vCoatColorInfos; +uniform mat4 coatColorMatrix; +#endif + +#ifdef COAT_ROUGHNESS +uniform vec2 vCoatRoughnessInfos; +uniform mat4 coatRoughnessMatrix; +#endif + +#ifdef COAT_ROUGHNESS_ANISOTROPY +uniform vec2 vCoatRoughnessAnisotropyInfos; +uniform mat4 coatRoughnessAnisotropyMatrix; +#endif + +#ifdef COAT_IOR +uniform vec2 vCoatIorInfos; +uniform mat4 coatIorMatrix; +#endif + +#ifdef COAT_DARKENING +uniform vec2 vCoatDarkeningInfos; +uniform mat4 coatDarkeningMatrix; +#endif + #ifdef GEOMETRY_NORMAL uniform vec2 vGeometryNormalInfos; uniform mat4 geometryNormalMatrix; @@ -66,6 +91,11 @@ uniform vec2 vGeometryCoatNormalInfos; uniform mat4 geometryCoatNormalMatrix; #endif +#ifdef GEOMETRY_OPACITY +uniform mat4 geometryOpacityMatrix; +uniform vec2 vGeometryOpacityInfos; +#endif + #ifdef POINTSIZE uniform float pointSize; #endif diff --git a/packages/dev/core/src/Shaders/openpbr.vertex.fx b/packages/dev/core/src/Shaders/openpbr.vertex.fx index 2de8d10f6ad..4a2613db5fe 100644 --- a/packages/dev/core/src/Shaders/openpbr.vertex.fx +++ b/packages/dev/core/src/Shaders/openpbr.vertex.fx @@ -42,6 +42,8 @@ attribute vec4 color; #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight) #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) +// #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy) +#include(_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) @@ -224,6 +226,8 @@ void main(void) { #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_MATRIXNAME_,coatWeight,_INFONAME_,CoatWeightInfos.x) #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) + // #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy,_MATRIXNAME_,coatRoughnessAnisotropy,_INFONAME_,CoatRoughnessAnisotropyInfos.x) + #include(_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening,_MATRIXNAME_,coatDarkening,_INFONAME_,CoatDarkeningInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_MATRIXNAME_,geometryCoatNormal,_INFONAME_,GeometryCoatNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx index 7ccdee198ec..f93442838b4 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrCoatLayerData.fx @@ -35,7 +35,7 @@ coat_weight = uniforms.vCoatWeight; coat_roughness = uniforms.vCoatRoughness; // coat_roughness_anisotropy = uniforms.vCoatRoughnessAnisotropy; coat_ior = uniforms.vCoatIor; -// coat_darkening = uniforms.vCoatDarkening; +coat_darkening = uniforms.vCoatDarkening; // Apply texture values to coat layer properties #ifdef COAT_WEIGHT diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx index ccbfaadc7ef..7f2b8ec7f4a 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrDirectLighting.fx @@ -82,12 +82,35 @@ } #endif + var coatAbsorption = vec3f(1.0f); + if (coat_weight > 0.0) { + // __________ Coat Darkening _____________ + let cosTheta_view: f32 = max(preInfoCoat{X}.NdotV, 0.001f); + let cosTheta_light: f32 = max(preInfoCoat{X}.NdotL, 0.001f); + + // Fresnel reflectance for view direction + let fresnel_view: f32 = coatReflectance.F0 + (1.0f - coatReflectance.F0) * pow(1.0f - cosTheta_view, 5.0); + + // Fresnel reflectance for light direction + let fresnel_light: f32 = coatReflectance.F0 + (1.0f - coatReflectance.F0) * pow(1.0f - cosTheta_light, 5.0); + + // Average reflectance for the round trip (light in, view out) + let averageReflectance: f32 = (fresnel_view + fresnel_light) * 0.5; + + // Calculate transmission through multiple internal reflections + // This uses the geometric series for infinite reflections: + // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² + let effectiveReflectance: f32 = averageReflectance * coat_weight; + let transmission: f32 = (1.0f - effectiveReflectance) / (1.0f + effectiveReflectance); + coatAbsorption = coat_color * mix(1.0f, transmission, coat_darkening); + } + slab_diffuse *= base_color.rgb; let material_opaque_base: vec3f = mix(slab_diffuse, slab_subsurface, subsurface_weight); let material_dielectric_base: vec3f = mix(material_opaque_base, slab_translucent, transmission_weight); let material_dielectric_gloss: vec3f = layer(material_dielectric_base, slab_glossy, specularFresnel, vec3f(1.0), specular_color); let material_base_substrate: vec3f = mix(material_dielectric_gloss, slab_metal, base_metalness); - let material_coated_base: vec3f = layer(material_base_substrate, slab_coat, coatFresnel, coat_color, vec3f(1.0)); + let material_coated_base: vec3f = layer(material_base_substrate, slab_coat, coatFresnel, coatAbsorption, vec3f(1.0)); material_surface_direct += mix(material_coated_base, slab_fuzz, fuzz_weight); } #endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx index d11fb83c00c..1e04a59b1c5 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx @@ -108,8 +108,26 @@ slab_metal_ibl = baseSpecularEnvironmentLight * conductorIblFresnel * uniforms.vLightingIntensity.z; // _____________________________ Coat Layer IBL _____________________________ + var coatAbsorption = vec3f(1.0); if (coat_weight > 0.0) { slab_coat_ibl = coatEnvironmentLight * uniforms.vLightingIntensity.z; + + // __________ Coat Darkening _____________ + // Hemisphere-averaged Fresnel (empirical approximation) + let hemisphere_avg_fresnel: f32 = coatReflectance.F0 + 0.5f * (1.0f - coatReflectance.F0); + var averageReflectance = (coatIblFresnel + hemisphere_avg_fresnel) * 0.5f; + + // Account for roughness - rougher surfaces have more diffuse internal reflections + // This reduces the darkening effect as roughness increases + let roughnessFactor = 1.0f - coat_roughness * 0.5f; + averageReflectance *= roughnessFactor; + + // Calculate transmission through multiple internal reflections + // This uses the geometric series for infinite reflections: + // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² + let effectiveReflectance = averageReflectance * coat_weight; + let transmission = (1.0f - effectiveReflectance) / (1.0f + effectiveReflectance); + coatAbsorption = coat_color * mix(1.0f, transmission, coat_darkening); } // TEMP @@ -125,7 +143,7 @@ let material_dielectric_base_ibl: vec3f = mix(material_opaque_base_ibl, slab_translucent_base_ibl, transmission_weight); let material_dielectric_gloss_ibl: vec3f = layer(material_dielectric_base_ibl, slab_glossy_ibl, dielectricIblFresnel, vec3f(1.0f), specular_color); let material_base_substrate_ibl: vec3f = mix(material_dielectric_gloss_ibl, slab_metal_ibl, base_metalness); - let material_coated_base_ibl: vec3f = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coat_color, vec3f(1.0f)); + let material_coated_base_ibl: vec3f = layer(material_base_substrate_ibl, slab_coat_ibl, coatIblFresnel, coatAbsorption, vec3f(1.0f)); material_surface_ibl = mix(material_coated_base_ibl, slab_fuzz_ibl, fuzz_weight); #endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx index 0449c84c80e..b2d3a715bef 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrFragmentSamplersDeclaration.fx @@ -7,6 +7,8 @@ #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_SAMPLERNAME_,coatWeight) #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor,_SAMPLERNAME_,coatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_SAMPLERNAME_,coatRoughness) +// #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy,_SAMPLERNAME_,coatRoughnessAnisotropy) +#include (_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening,_SAMPLERNAME_,coatDarkening) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_SAMPLERNAME_,geometryOpacity) #include(_DEFINENAME_,EMISSION_COLOR,_VARYINGNAME_,EmissionColor,_SAMPLERNAME_,emissionColor) diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx index 32b7fe21f81..94d19221652 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrUboDeclaration.fx @@ -45,6 +45,7 @@ uniform vCoatWeight: f32; uniform vCoatColor: vec3f; uniform vCoatRoughness: f32; uniform vCoatIor: f32; +uniform vCoatDarkening : f32; uniform vEmissionColor: vec3f; uniform vBaseWeightInfos: vec2f; @@ -65,6 +66,8 @@ uniform vCoatColorInfos: vec2f; uniform coatColorMatrix: mat4x4f; uniform vCoatRoughnessInfos: vec2f; uniform coatRoughnessMatrix: mat4x4f; +uniform vCoatDarkeningInfos : vec2f; +uniform coatDarkeningMatrix : mat4x4f; uniform vGeometryNormalInfos: vec2f; uniform geometryNormalMatrix: mat4x4f; uniform vGeometryCoatNormalInfos: vec2f; diff --git a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx index d35d0e8aecd..027c4717a0a 100644 --- a/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/openpbr.vertex.fx @@ -38,6 +38,8 @@ attribute color: vec4f; #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight) #include(_DEFINENAME_,COAT_COLOR,_VARYINGNAME_,CoatColor) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness) +// #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy +#include(_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal) #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity) @@ -212,6 +214,8 @@ fn main(input : VertexInputs) -> FragmentInputs { #include(_DEFINENAME_,COAT_WEIGHT,_VARYINGNAME_,CoatWeight,_MATRIXNAME_,coatWeight,_INFONAME_,CoatWeightInfos.x) #include(_DEFINENAME_,COAT_COLOR,_VARYNAME_,CoatColor,_MATRIXNAME_,coatColor,_INFONAME_,CoatColorInfos.x) #include(_DEFINENAME_,COAT_ROUGHNESS,_VARYINGNAME_,CoatRoughness,_MATRIXNAME_,coatRoughness,_INFONAME_,CoatRoughnessInfos.x) + // #include(_DEFINENAME_,COAT_ROUGHNESS_ANISOTROPY,_VARYINGNAME_,CoatRoughnessAnisotropy,_MATRIXNAME_,coatRoughnessAnisotropy,_INFONAME_,CoatRoughnessAnisotropyInfos.x) + #include(_DEFINENAME_,COAT_DARKENING,_VARYINGNAME_,CoatDarkening,_MATRIXNAME_,coatDarkening,_INFONAME_,CoatDarkeningInfos.x) #include(_DEFINENAME_,GEOMETRY_NORMAL,_VARYINGNAME_,GeometryNormal,_MATRIXNAME_,geometryNormal,_INFONAME_,GeometryNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_COAT_NORMAL,_VARYINGNAME_,GeometryCoatNormal,_MATRIXNAME_,geometryCoatNormal,_INFONAME_,GeometryCoatNormalInfos.x) #include(_DEFINENAME_,GEOMETRY_OPACITY,_VARYINGNAME_,GeometryOpacity,_MATRIXNAME_,geometryOpacity,_INFONAME_,GeometryOpacityInfos.x) diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Coat-Darkening.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Coat-Darkening.png new file mode 100644 index 0000000000000000000000000000000000000000..44a4e20f89544bdb70084cfd2492a813e157a03b GIT binary patch literal 38084 zcmd3t_cvUB)bB^{z4yUrql@TK#tfsk(M2aBh!QQ)dvv3OMDM*ui{4uj1VKnd5JYsM zbC2)y+;#tjd;DOnS>yQBUEce(U+ZeCk`OWyfz^|Lqz}g^YOfFlSMuXc&IAoYTPgp1`s-{6$gHr(P*P z6ju?1MNS=^HatA+qFEZJjULmK8GVrw@A&1exBa7%on51JJjv#jJ!b-3z3}8UM3EeV zZ~Oe@NAr3v1A~TRP;^<)i*s654HdZI)xK^94MRG^E&tistNjbFvoG5-bxe%^J(B$6 z{t6*c_m4{M6s)`ecsvZ0i3;vN8P*~ZjQF3gJ$z5@>;yc^v;RMSss1Pkl%RRI)N=#v zz7@XPxEnh)^&DPo8X+0T)GiCYJL?(00zObCa|O{T++Aq@m_+j=GB=EG9KDdq(JrGC z#`RZ7RPo`>k-vHQV=_NQ{&prmqD5e$v0A-EzXIj5)Z*Gvjab z$w$!k2Sz>*zB2XG6MCaH^Io9Jtmf;^sY+2pV`F1?chJw?(1Zk%&Yq=R%MPF2%hR2X zjt*c_EBmsEYyOtx*fZNF!8dhz>+@-Fzr&#`!3ijZBFtr}cFwuktj4kqm=k@}rhnoZ zakTP?hsAv4Z#*T%%C)560KR>Rp+UQ(?`AbdN>?NUprRy&Lma-K^S7P&wj#`=3RfS; zI+uKnrtM^&G zTj|qpEstxAHh=%l$jBgNmU2JYn*Q`jYnmtEXpF}y;Be^cSEG*ati-tac=^~-HrIJ~ z$H&CxRBTTsS?f^H>KZ&6Yyt}t6BBcD*?{wd-@kufUVeD`w#H~@Je~iIu+{MIBo)q; zGd&`VwL?ES*1MCk`6IUyO4e6@znayk40VHEkWM`i(ee_@I`7`UlD}SQSWP1afh9h? zc$#f>#qo3Sb^6OLH&fazHm17<7(Fz4fz4umPHi?2^hmWW`f&HT0#U)c{VP8T7q&$E zkBLTAhGVL(Zf^fxcCETgF($}O9tW}&VvEFB-TZk3jQ%Gco5PoCDZlL!JifT3QWC48 zV3229LxWxgig;jQVc{UKXMX4OWmlgyXj|;)xf-`lj*J{@Qt-c~nvd_wW6Scob3O&5 zT|iR`xZ*A1XU1FY6Gsti(r=EXp{Tzag zE=m(Ow61Yk8t&x9j@;SVStgSUzP%obqibzxF{`2F<@m^Gi;7q|n!LOAZ*e8T;0oo4 zOZovKZ+w6Mh)YU7dHdT*{Lksj8l$SEU47S)ZRL1e5i$Ctk^P>Pk3~bU5bU?5W862R zG10Nbm^ z@XtXNCfB;6)_o-LqviOQ`iWH0JlfUbj3g6{ZBK2yo8!tNT`Fomr|q#ju`e^7|CY=P z)ns}4hU-?|lu9XD2DNxY<}HVFLXWtPStrtGQ0%h+XZ|-zu2N2<6uu?xuj2sri_0!14lP70XW5n0Nwq&pB+&pf+j>r_;@!5O= z$N4%0VnPXtqg#gT6iL-dqX$YD4)ar(U$WRJ9RdreuR+(wnJTNkM(_keV%_X6$GYO7 z8c2I=57v4+)MGHm`cEZ0+E*TrF4jdCL>0w2>5JwX_(*8d^($tbP8?I1 zB5)`(NlUtAXb6Y{jrA=jO7)$azdDJF#Sc^%6r?bl;m5_)1>X>?oFNRMltf4_J>{LB zhMM8amz;nDB*z{}H0(a_*GM7M?L$FCaA^u!U*q$ot1~gB?(T|@&{gK!dYW`SK8!K+ zm=1}(xN!T>-lxhcjjBM6zOA6<5=kRzSw$~mAKAGs{p;i}LA!_ZBy{FS*1P*1e;QH3 zLEscx=&mITdZ)w`#vVluD_S27uN?}uX1)>D(J%OQvANIbJ4O)bNt==}SP?!!uZEB9 zT2;07-gzr8;3(5|X?ct1h|e+amU7QM7@sl>*u5F*ROcrDW}#wH@cR@7W$Ihhf#AdWL?@Wq!3|$ zQqdhTNfy{_=E`m57<9Cb5s!nASBf_U(Kxo{#4_9d)%n8@vM;DpQ3BS$#P4)Yb-`bW zzGVHSyFQNI!2(I7T5^$|Ehe?GlWrca@BzWd+F@UKdPJ)IdT0K+KkDS21`eHt1pH5o zEU|kJkz|Xd8KaMkSA)Nl_a6}kBIs{~p-b1g2G{Neu41(~xwJ^9$+el6xm znNbcBd=f&N@&PLr8B`n#o&4Q(U_n&;rTz)c)bnI`Dg?I6GXLkbqCBN;C|>xWa*dHe z7G2tAYr8YcH^MQJzYSV0c?IRXZzeLDS+JQjsnXr|yW(_N1}gK_S2Ef>1RhYs**-fc zqm%js^MC`_9xx{UJV7;5<67m)tpI`cCOEcj*>0!T1Y}F>UT6DE25EuX_UalqxY0%^hvny=5Lw9 z%FX+O6JV*k&gPCItfGPV^kmWcieN63eNggK&EdHsid8~V!^_KSwlm+BG|xeWdL-@} z)6;r)Ux$8a(&gV{;-ALW!(7=CruoJ7qXE0{vw2?IgUB9at@<%4&M2@OBR+*RA270Gy~2lh`sFXLRY>nZu{Ncj;-#M+&P1R!a=N`IZF z8YO8F*vgaFjZF0eVPiUR2s~-TTeXc2k&xb50;3zkT}o)c8lai!l+R+0hvQ^3k6mJ; z<*UDt%yvY`ke$EPhqv82lv)LprKRj{P?aZt)<+y>|`#ghVL&C|0trI?b%+tqhI*99b9%w#NgHWqSs) zl#r=pjj+KRvQrRbeyk|&VCI1RP#q#D=YIrhc7r4Cc-fHHM>^~8k@y8Kt0PFnG>9YM zZ-wN70vMbl+gxH!gx?>lGUCT}Q#^be%Ok!@(sqTttjLmAm_qlS{CCnDtDu-~x=clc zCv5!bgxL>!8X7zfe)gT7o<>GSg7LrY{`>lsHv1D150cldmG^@XG{Mf`(K?tX)f%k5 zo}NIW;eq&`^}shY-Xk(r#)5p!ZmET2;6QHDgZcc}vz@qr9Zha{fl}O^j=f4R>cSey z3kdS=E$BltgBNA4%TgZ{EnkbAJ{9;i-9HYh56ydx>cuk2_(K`SsVd-k3c0xE*dQ`g z%D|p(9mx-K!1Y;B8c8`Kh#Jt@{Jn?Tp=N9fqwUW={PwI&rHEp~G?g8Pwep9PxP*j+ zTgPsT?0#p{v{P?hU2Uy4cWR&Y)Xpi~Tx28$XX6x{W`e5};{SN51;;yl^;MkQ&B-n$ z4J6KSHRgMJd;8GP5HNk`W*OF`s~dTNA0k>ncG0+6_&d%mnR_?qmcWMDxI1Jr+Jn=Et8$@p)@kN7*4C$1JC}ubrQ6ck4pM9q|MsqzAkoOANukJ*4h0DJfBoCjIU` z|M>X0=SOFQWu35)5PB!hP{rE?VZSRs99cA7KC@k2T|Mjk5ISNGO-E&r$Dj+>Niv@U zzCSK5j){p02r*Az21+q!OgPMYi$-&kk=nk0Bu=36P1Y~>W!LB1Cx(jLh(%D0R;=v} z4!tS9CZfO{7Q>7wq^CPJw|~ZzfIF0HLto(EC%ac}@G4HjGD0Q7A{h3=#9t-NRm@xn z?oBy)%$-UQPtl2YHa#~=bjg;?^Eu}gC>!3=269vEu&Oa)N*KPpl&J{wOLB7O#+V=X z;v&}!2CgS@(VX)`#)S5EX`lX&BKENJS%cP;vj@RfJHs68!0>^wN0YGuX_Tz2>~}Xh zWjxA1S&A2Muy-VpJ+MpzBFrPEW@eQ}Rp*bRY*0|+4JK{*qfvI}-A*{>7%u~a?JK>(1QQ8esK@=F-fVXB z*|&S(;UV;WRdR1P7X~?I>52&PC_^&J8uuL$J|0)i@cdt$iN@}$@B4*GqqqJ}RqYVu zCCx(_6DU}JMxf+w&nes(@WTpmL|BtpMizhk z_!r2=(ZA}x<sQfQ>clS&}g7ud#Q38W9k&Ro(A|^A!J>?ra4(OpD zaAoG4YpSbz`w0d_T3T8F2YU?6)2)?AiQPG*kak!b*Y;%XN`BV4(MjUn#KeR>WZnsX zo@_KS8JZK_o)OezCGf3E2S7c@xrDrGhV_`0wZrw zUGJ_Tg4)9nV~4VAhHnnfmNQDZw^50JJ%4Ez%}UwYpqgm1T+FKxw(2EiYkgilXgb4hiD$r>Od&W{%Z9Vp)gB&qYg13;6Dym6gTC#c$uf zEiM9QJ5pqpv{728c6H6{P86g5MOvOl;di$Iw0!+-;u<}!U__bD^H>P^C$8?u8STs` z{BI_}!vm|yN4T(rx7pZ2(HuoO+9aN<{+4Ak>@Aq*h5FJe-@Sef63)5D5~_(pJ`?HR zH6kJ9_IEHA%ysxWJ3|!U(CUfXmTufV4lV!SE}JC2BTIfWHfjY%{zFNnOx}%UrJRs- z3N7-Q*nORXWs>Cv{&Rb=+AjGMjNP#>MOyuqjTl!qZC^?oxCA~OK>oPN1fN!fG$C)= zM^BWc7Iq@D)yW+pCNgMIQ zK-i#iYb=nbx+WT25--(JHn3ud50w2b)4U z^e|HzQc<{`T0Q$$%i`cTpAM4J74c8%8{b~Mj0vDynji_`&3BE&1AWlV6a|-Z^iL7j zt4obGdlZ}ZYNs{2KlYVk#-velpKeV2X%0mE^}A4vWH^CsRsP^f(<60Dga85FSYpG6 z5952ao+ss>K2yX%lFc7->ckFba-+!bDstwg)X)YPJFX`LTK-BzHuAl$+`P%sigN#0 z$_VZsYe_5~ut^^wH{i zU+lmn$?6))u2xPp&wK$rm?S^DZ5W z`(=d;g{LU*2E%AhNCcGEH@EG(nzpu6Y-R~8MKa+qR(d)oINu68znn>JEsyTS?) z-%YV4G0DUh8f$W2nVUKHv`sf~a*R0WAz7KbqmAgL5 zv^buk^u(2O&@9U0afkM7WE1}dDsLhUdg zt4GZ1`VH-->io>{#bF!@ik75|W(q?!?`Ukq85jQwd>H;?*%I)*Z?I78tX;g)|JY~zA%NDXN6u>nG zG{rl1nnG_*bW77bRV8>LT)hrl6~j3chCg{Me|>Ou=rkKc!b0Il;!e5va(YUiqLa7L z>WEht#R+BDLJBms|`Y(i|1wt5yz;O@G#L z6Bl5@Evto{<+h|EX$3 z4rHhl_C&P_NK~rXUtdF-Y%Pv?8l2E!6o}N3jEF)0WE)Y|r09XwF9|G;Fs+_TNb>T> zit>C8CN*yL4RS5kGRm9c!mw)E;apya&=L-mV1qrJ*C&2zUCCu7W*0Kn#Lal`(Z1?d z5K@$2FCGevdyIv{BsP`1xgUgDpFEm;*1E)pRwOLorPkIb;ng`)`vI)?mqi_89AT^5 zF}tKkQ8fL9Bo6vXL9m&Szr|q5%h!6`Pz*!H93xBAFD3Qim_fmxjTlph%a(vB&fGiK z?q^^N#WI&?Q^`^oZ_Uv=@!A+qABfiRSX=WewIU^8*Lz@{j1~VFJWx2Z4T$R!MxLZK zGE9^m!jd-@v289tW4}O#45&vr%NKk%_!|&Z!4;Gs)P({Y<%{EBHOP=asN8K?_3JC?jA^EabMi1(``FFN(5>h^=m%~n>!2w;@4smi8`QBZS!ter~`4IIbMDOwU za*6`TA;PdbL8XYA%8EmxO;p!Ov6=&S_L=%EO<6#4GAh;)AqQ%Eddz@OD1ah&^Hl^{ z)Fk=F8!_r=u2fLk@Id7fyBNaPPh|AP9SH>^OqCsQdDX;3q6izmvVF2JLy&VoQGdG! zdlBO_RaIc$8T$p{S3WN8R6|cMutib2ZYS)9BAk@yla0bAqyugk(Lo+#7|QF8Ep6FB8=YO+A38pg}NNm#flN0ivAkb4tTqAmLb z-{w?A7n|HFH;WR`q@a?uXo~l!6f;aX9{^#ULFZi%6`2(dq>cbJ8K?Ot8?3#vXCO6sdeZn8W+2mq)jl<2z(1A7^=b zH-RuDJ0iK<0M}Cj{kNe^kJ*X+BctaG+tQ^5_ZWQizRYxtdzR-kjTZFm65&a+e7*Eblz@^j{r$JUM> z7eXBh(+GWJa$NjkAQ7Gtv&Q(;x;UJOh{M0#*?33I7C0;;1rqq#EHv)FVj~E>dDQf! zOXwMj2!9P%PCYs)&A-Am!*9Yhhh&YXnG|~-EE`UV#8158Xy@x7S$p{9w%d&0fv_p>do zdI!AINi2Ei)WGrcai@S`a!Hsckv>7lte4f_PHRUfKF>a?%Fth4w>HufM){R6l+e-c zY!$-qU0FJ{VK&z%OB|iN zpspn#q2l|EMKwI~^b^{#E-cChNJGg6_L>v2-3bT~5a{~5Z6})LU?9YKXf58@K@e>g z>^(py)9>{$2L1ClmLWP6nxQQ!P@0iwpG8qp-W!mweik#XQao1Qi6RfP3xIv$$uCDb z6rvgwRjPh|0s(t~r6Tq0x1%vhpINY++CyQQ2nYSOLwW(0GkR_Wlv;y*T`0I4il0JW z4t8c&LqY`CWw1H&LS!Gtd>`=0j<4bfx3-gG%_>#Pozl=R(C6eFry6}03BMY9O4G@Z zA1U%ITVbD7)`+5{2cAJH)W~V^Xj8cooXhgoSO8yfN7(cFi6mQ;cZk!;gU>OID3c6B zXnNamsh(DFXFTuRqef$;;(l?hV%Yn6C*nLX`qiL}S{7pX<-@>#z#3q=)34Qu60XjA z$zRmcrCGmPk_nJ1R+m4$5YbE6sy6;Kv3k|*x>UjhUeTAlX_yIdQ4tSMr=*^`#8a|f zlE~t9tcZEbk=SYin~(V+cmKj){x{VPaf~1ubsUVX)275=Gl#gD;u&V>8^H5|A${luo&1zXfJ_5=f7?LB(bnCg zt|I;}5WWF^prAxvZ=)N(*tftiZMx4{Nt$mflcOJphq_cjng06lV)&lK%Bi(yUGs!SODW<_3u(G555;* z7y|NhSrVL&APqmOC+XrtgMth6J;rVvU{5sdc%m0$7XxY)Yc*MH< z@a`PI7%&;ARn&2ZV{rOD(oB81=q3vV`;MRGJ&*=a^bXW3OtNq*e(Eol{oM2Uk)xk$|sSGY9EMx<#J0+hhmxEi91Q<(q@@H@(=s-^R9vXTviof=0GC5lwaPy@k9>vlfOIj1+?rf}E+ z3QTe#mCr-jf)7EWId$I!sO@|yd#709Vsgkwz_o(n>m_JgO z;U8n~iAI5=#r>V~V!P}%rDLC;VJOwxyww`Nj3z9IAdwLJ+$A0rF}uz}8Ybw{9ebKo z8J5ZRxp9mGS?qdz1D!ydGN|co=0HJ}1h{ys8cT+09TrHH2W4zClKD%dcs5?lubQOKH zNZjNZE%hh3Bv4#A zi!v1}mTNKY3 zXT*Ap%;!gwMVh%XOyrl;5*YNaW5e;-ek@-2H=Ct*;CM>>8!>IfBa;ufx$Mx@82Usr zv8ecF`naj@ zkseiDr_k1P>^0H2P=kw-E52DJ2a&P{oPTT1L!&_J{(8*97khL?dI5lpPRN}aUh-uK zj1L)3Bn*soIZL(nIQ(I>^JY0e`4btPck4%C_LjAt?%SWIJNu1>4>%<1=^J$;8zHs^ z)B9(D)b5MNF>Y17z*}8bKG63|k;o?0+Eg{*uIbS4V^p})Uy&0&Gjucp?a|%nY5VHx z(UFu40TWI(mIehFG)t)Ac9ME!lvRNI!nOBd=i><59oBlRX={iB;HUOAR*-hIyxVuG z(^I=aF=j|dIQt3T?*;+^{cU68y6*6=d6Y2gqD;d^YP7-O7|&fybPE=8M&~mvPtXDb zN4n7AYV^vJxTlNVdJDYd`896SKy4~!;rk6vhq?QSa@GGCZ55YM+-;sIAjXtR2PzUJ0~dUEnY+^jFaF!`5qTFRQw}13lvsBY}Fl(G{E4cCTl+< zOh5v)?z7~pkV#`qwRLTTM^sWNX0j~VPytMt1wa6xM~nwJe?{IBhWy4TsF;eu7L0hs zl*OeHM}-rcT(Zl5R6Z>S7N=p11zw{g(jnT@`f^m$^}o@8{tB{+!-3CNlD}rI?67bm zmdb!30+YzWBOwId{eXi@J1*}!K7s!C^PWT^EgTLg%~d)cfNn_=-5v)A;b=RTkk*M3 zul3x{_l#X_iw(_p|Eu4MIqtc5XSIImWV*(0)t)N%88gWP;56*$VxK4>0p6}8rv zS!i)nt(*lP#(lS7)8YgwNXvQWWOu9n$&UcsXXd@@Qp@gtWR$>!m=;x{@Ihd(IAeS5 zj(_f^zY@77ck11t!mafFhz?0z_a#1k8zqL+C(_z*!e61kL2`?Gcnasd`?SSTo4Flt zgxLZx#YV~ZmqKP#41H8 zoBrMVI^3!H6(?Q$T{*r@zkZ(1>!hvE8<(oaenB%m)NN z{S?$Gg3kvgkK7D2I}iE^j_A!P-6?|fY1tx^DFIXPube~va8OTbIrED`wrnpm!MtET zoFY4%Ox|g89-JUv5a~X-wzLvN` zFK@r7wd{I%`ezPMi?z!hFq5iDLn3X&vi?I|o>^h%-=>VY2hi0jw}gBo4$w0x+JtlKgjYa*nkTij8iI#q=8H3 z5tHzzk6&MRZh2|WECZYbF)lex=);IfjLowutF9+9IT;fh`@weu#7lG-fyH=na*1FP-1`sBXy=5$P zKHe4XC`1ac=UBGq*f{vqcxh=#iTr0@Pc=3N0l1Lt(R)CzSPAaQvNCt@`%|$5VF&Yh zx(B+s?M>ePoxI&jx*hfYt}7U!5c>CJvsu@^JU>3BVDu}x|9B^WieVR|zMzc{$fT=A zL4hiijg5`B_vuuDa_e^=^P=gWK|e2!H-#YJMZRPJRL>lOwBO{f<3+;v&-rFd0T z6jqVqm)<_26N2Pqpe83N+1l2I|N56oknSH8Y<-{hG|Rf{N?C>kpd_B!T| z-EQ8v15>jfiiT|UDKdb5;ca#rNZS~JcoVRVw~c%Ltk1hKf%%|wF45o4@vZ%>6n@xT_ek^WO`L%IL;k4P7zI%hWO{sK4fhSGR&Je!GUpzu z5ir73u4%WojgK7v$WSZU=H53M8T;VL9wxNywJrhA5v~d$`B?iv99_7D-&72cfxp7) zIb_l?I3=?18ZN~iBc_jluU8XX9wpNbAY;&qduNyctTuegd2gR+Mn)6leZP|TnTbN7 zw&BmG=>VKZSc7#`F&P?2oGvuPtJ+^3UH{l=Y zNLH+EM8b$&P2{~3D_r{|$wv2SkvB@oMQ#w6d|3o3W(@!IAgfe*=b>R;r)Q&u5dYg^ zdIR|*ojCY;^#s@F+((JiI&v_M$MI+UetPq@9$$q^@l6<&TnVWjeoVKB_l?9psPC%T zIVJ+!$k34a^G9P^(TxMb;*ejTSzqJU+ty&qK{`Q#*XL`u@#TIS>8Z%HW-v)8j=SYzUifhz`w|i<;9PzStj)asc~9ug>=Q-BSzt1>+mLe z_M9y$>XG)*FAZk+i5JsFJ|7U_!adiza&f{+F5akFSZ{&y#tW+ONrhmm_w@E7)fGs`Tb&M|huYED(zT;b!Cj({nj)J*Bqj z#&$owk`p}-zpB9$7hMx*x`gD!QygXCt`l%t%do`CQB+lM;<^L@Pz5h}A6BrL*ORo& zB^RZWTxeMtjH%!7UR;x36hGS0y$tz;Co~pcYn47qudbEli8KvV{0o2>*kafMqNvG+ z-I*@;2$T7NT7u5mKOOl?wIK9N_~e7~}u?1Al+(j7mW-BHUjsUd2KCMN zyeFq6a{r4}Wq2UeK^Vpy^j8!U;Kc*T1k>A+X<#O0!9PQCiq(G&(d`?L>3Bwly1GCF z_l0RKNQx{QUzl#$_MMXuMho`Na%+KD$_Zcdb!g6oJ2G0L$c_3JknH2nNCeyR3; zK5ppIs8dHJ$4FoYINJrjZ6Me#l1UvUrl-J?ql zi&IECfR+n0whD|8q#E+A5S;nB#Z25|ZKd0mDu*Uu*MX?x${A-?%vW>U1m5+9&(TYN zp|g|<&70hFRY5#H4-0@E;KDN!9ZY5e8bhmBi(ELKS*}|7tl2WNV{>oZ2~3-#mJlf2 z72dKi7h&HC9Jl96Y;H0+!xMyPo>BhKMB_Ovx*yn99Tf zwh6O5jDwESM>V{ra8=h-$`%(z?n4;KPMD{hPNyQspB(R1>%p!?T%s1GmjoXINcoMg z35Ai>??QO&Bc)LkT+bsL*%yOJ^^4parngS7h*HXd2%#1^V|~PHdXh{~0havkNRvVX z8xX0SE8VG8Da34@X20vKn5`!KrHeOD5Bo%wq2%9mShUN!gAz7Gi3{)3Qk21H(V{n*e3PZ6Y-szUX2d z#h@aY@*&Fg5znVKO@n_{ZcU@2(x;*)Ml`4XEqE`X) zG1rVZpYdc%y5p$8L}9M3`~@8&#pizh!Y|SSH0vUvn!^4`4v)n?nJWWll?Bj}h>!67 zDDCxU8wK$3Bqb#F+SU>WqRH0s04_c~J-wzza3O@PZeqk0ZKFe@9@0t_&8W>ymDy?k zzz+Is6hfvFB}-2#!I%I9!ob#CT=-8Ozy0J$j-9yX{%mILp+$FEnE3!YI(Pq{mNuIapzm(;BJltNW>zz-O)>Tg=Zb7&_z?uG-r~B{ zC_vnAJNT$T5~+`aLc+O;FK@cnq=5frUkCKSq^l#1bQ^tg0a=P5SmQ8R_k05qp^pLL zdFtj?Yg83@Ve{Fzs&z~@YWQzHkMl9Mp+#?PK(A)L>k<&RP5%^7@nIhEek^B@n?AQ* z^q3>sdi%c)l_;CG+K#3sAm0GS8t?Bne|FO@y~waPYwSfAnj8^A`}xzSPm_}?foI

0Ze9ITUyEdPACkE=9Xlk<=}jHrc82GZxQuwFh6|Ke(7J{-9?@k zQPdoT494(d)aTRWpTVmigsy$R?Mj>&q6yXB+>`g`B87LQNFt4rFTOojkH?wfKE1|2 zIz6pk!#@-)KD@e-e?k0{9sk7RpFd1BqJ1@zPCMjgK(e z@lZVNwCb9yL1K)7cPy9Ze z+>uJ$zshu`O#wHA7mn(@;CXh*4(i{0@p#_*`^LrwfO5%q#t>KYPy_7&59|}1$gzXZ zql1xR$%Jj$NM=lZoIaBNvfa~{Q>!V_o)-W~N~4D%JldOh6?S#(8+_*bc)nyb&Hf!< zd8)F0-zlS-#KCc&BoOTP%k{aRZ!a(BT)P#B+5zGmNt%Y~c1Uy2vDARg4-{0i+$f6zN<)(gi^8V)5!<{5&#nYF%0ocYpSK(>EYE z=fiFv-aO*9e5G-+S(sPq0gcInzEhaKB>!uiP!hM{N$D&?%0L$Lz}5o| zDgba*q4)2Akfw^x`KX+q9@Iyij9vecf+(1lZu^1Lf;jk;wmF;;dxRVgY=|s@;vzIE zyg;n?VOaI{NK5KGmrtJeg<5YnUgnk~K%uZ^eCN_W3X`jjed*#BNOEg4%gXU2{O|kl zK1Dc!92=lHULkHKI>^3zO@@sM+jk_WH#o(ni%|xx^VzDcC_+yhm;Z;_Nsj!W?Wz~$ zG3+EB_HZq{4@CP%3FaxqER(1_H&K6OigY|xeh`XoAn|Z^vh(%v0r*zyY}rIR`uF68 z{)L(f{$vl0u|3%7Nj+s^m#(Ki;1Wn5xs!+6o%^_1reQz53IAE>z|z;s8sPp&pBi6y zR0z^AU+BB074>?Vv-0_91)wI0(7V?teEp;j5kcKSpydnpE>dp@r5{kU7u?#G&4gOA z_h|jcLt*8<+WRr>1a}MU$HWC1TP#AqJ*#JFv&C>e0Q0GrVs8)#jp38AEEWGjq6?{8 zT3eq-C>f=jnBM^^mu_kHOQlfpZpZ_B`{7t4xrlGFP=w~!QRLM23+ui-2UB}pB+F+- z0?_=W#-L(XLLn*nTeCMOBqmb~>XB%9) zb5RHkAW5~nUR`x1Bt-Xjq^MNhSK+|IgmqlBd4gnpEVK38n8Wm)KcS)OK5??g6lOGq zw%bVYcUmU@L=^6Ju$GcaI zPuAqH`AY3TfX8Y~0H@89J#UW$twSGWGR8wAbdf;EBlAcfOv#frxdbNm3~9MKo*8@o z`dh8j<(Rm&6L)gIwFuBLm3xLL@g#N}LIq%+@`+B<5Ws;Fdu6tRvgHZ9V9wbPN^?zf zwhE61f59$@NM2vfx5c1PLl!3jO1K(STr33^YWpy5sxkP~(+j zD>g*xHZq5CMMT&;i#WRzgNf95Z&H!@PWmF>-9=u+k1pcpu%zh%zSq`mi63)Ub3v4Qg*5%fN9UW0bzIv!1o(L4w{bCA2Nkg8| zHbkJ)Mfa9XwoqBifAoCVXzNGZy6<~7(bvO263cg z()|&~Hii7?C?1_yZX2v$qnxVU_9@i-4sDM)a>*NWl*BxQbZFq8GB^uyQy9m9%HuP4 zLwIrAGX867*z0c<7H{I8_*jp;W3+DoT1tVI#Tv%cG3-A>8~%Fj#PyCssC_`dIQo#C z5CL0ok$B$oy?4{t3Yy;^4hKOj!_@6Hx!2V?@&?0{t+g^f|I#nil{iw5RsWzGU(Cy) z!d!8m`#0hG8VQ^W`Sz|w3JB)Lj$*HD;X`;Y*whJv;z zG3u@#s$}x#;6-O|=r4kTfLs$%F~=Q8g!vyhCc~WvUHUM7BFzzJ0?mQ{(rTm}C8a_q`x%5Y zUcmOZQn41;$GfdJ)NRw-I5Sv2%+?#{F`mc?`>5g5&DTEe*ze~0s*M18-M--NJ))#R zrS!fiVpFV|<2Xy_S|Qv}?b@|p!FLGXMJ^|%e1-GSr$I71)iLqDi4=>+^K2^*}n06{| z)QjPeo8&a_bKtbJM3J6e*Dni(D4*&V02riOr9B|Q6r=LgGNeFLWrS=KVO!L5McNoa(ueumuW9B751hn_6z}14WF6Y1zNXl zU0k0$Cai|b=!X1F|0e73qtJy`YL+5Ms?8sk@b_00O`(%&pDDQanbv92sT*tsVy=sG zMdnB8UnYteWJ@(rPR4j?n34ZAM~AYQ-70*6_-IOzx0+7dI1h-`KT0r*o#HKtKI#Q^QVjjQxrC(=NrQ2Jlfah?e?>T zW4dv@Ih0g1ooavO9lO2=;uM2)fI;$|Wg={fJa+!nc1UMrNio=k|KMg;D_WQD{P)5)DH5MIi7aYL;zbt@HKT4-q znk*j2z(Sx8NB&(*)Mu z>L2=ILYYKPsACodjRh;LX{VsCVNe-O-oGc5W=qhZVtM~IIJfXS&HT}YJ|%4tDqO?A zO)8x+A~wI`)v2W(cW$G#9{e*}l(zbnU4 z5_twa@IRP!IC`9(n6ftut_sV<%C7jX5O{fd=m(^sx&@6Jy2Lzu&h{U<0M_(!v^Wq8 zAb!G+ZrY1v(wEpNa|>a(sVd1Bq-R%%}p*#6A4AK!YYy>9}OEfP=_KrV$L+nZ|?W| zbDnP!OI0x|R^(;-vh%q>m7Piah#ipBzk0L0VXPM5;T7Uv0WQY2d5$r}Ff+?DuuwVr z*D$#llWd#Bo5(gITyJMo%t)#0t^6xs!Wc&nv109HUnF})`+A@NZf$3N;@vwtsbW@k zLc;c**rNfckb=W+>k_!-vwpeBCINouLMh9-$q&g^XC%D2avq;H{3)_-?>5@b)YhP+4 zG?$2tdVbulMe2kr5+xMX%MnwxItMNR5SF;n)6VzeAdPWF;CjA{cHH%hOuv6LAz-q#b%5cK1xuSiewNK76jQc z|Jsjs)iqa6@$POs(Lz>YhmS`nK7c&`h8^xah5>=TKZXw@)=QtaJ72JYKx#p++%}8z zJ#!M0gky_l{$sKD9lj+0BCQysx>CEOGA+i_tndGiFv)sgl|e3*m|_>L%>jXADKeOBQ??*$5>hOI+3i z6?xQPWZxZS_3(pts@>zIr?zBxz z{m6$RwZ}gd(+ECYCn}O+IUbS1&$K)i5PKy8?ChM+q@e9(_Zf?S_S!Ff%hH{7i zB}4!chL|`N{_m0`yEZWAJl@LxA$~778n9%Dhp!NTvFBX7s&O5zr^~yv>SO3SXFolo zbB7k!!ZX*Z1$3?MU=?z9lu{E#%oEZtC>;OL)~>tMQ3SsOVU+rJX9}Sx)Szq(eiy#S zOncBXD=BII9P`alO0}{izMK)4h*$E#6bgS3yonHnE1dPH*i>TuxDeCn-h3VD7*d

0qFzyoMNVHNK;(BOs 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 DbYrFB literal 0 HcmV?d00001 diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Coat-Darkening.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Coat-Darkening.png new file mode 100644 index 0000000000000000000000000000000000000000..ffa0f048fd2570d5ace0d6c47180be7b1b1ce35b GIT binary patch literal 105683 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 +ke`;eNR{!-jC4K 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 Date: Fri, 8 Aug 2025 15:18:12 -0700 Subject: [PATCH 42/45] Updates for coat darkening --- .../core/src/Materials/PBR/openPbrMaterial.ts | 4 +++- .../openpbrEnvironmentLighting.fx | 2 +- .../ShadersInclude/openpbrIblFunctions.fx | 12 ++++-------- .../openpbrEnvironmentLighting.fx | 2 +- .../ShadersInclude/openpbrIblFunctions.fx | 11 ++++------- .../openpbrMaterialPropertyGridComponent.tsx | 8 ++++++++ ...lytic-Lights-Coat-Darkening-vs-Coat-IOR.png | Bin 0 -> 38387 bytes .../OpenPBR-IBL-Coat-Darkening-vs-Coat-IOR.png | Bin 0 -> 116163 bytes .../tools/tests/test/visualization/config.json | 10 ++++++++++ 9 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-Analytic-Lights-Coat-Darkening-vs-Coat-IOR.png create mode 100644 packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Coat-Darkening-vs-Coat-IOR.png diff --git a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts index 58c038f29a4..b61e8aa0f0d 100644 --- a/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/openPbrMaterial.ts @@ -622,7 +622,7 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { public coatDarkening: number; @addAccessorsForMaterialProperty("_markAllSubMeshesAsTexturesDirty", "coatDarkening") // eslint-disable-next-line @typescript-eslint/no-unused-vars - private _coatDarkening: Property = new Property("coat_darkening", 0.0, "vCoatDarkening", 1, 0); + private _coatDarkening: Property = new Property("coat_darkening", 1.0, "vCoatDarkening", 1, 0); /** * Defines the amount that interreflections within the coat allow the underlying surface @@ -1344,6 +1344,8 @@ export class OpenPBRMaterial extends OpenPBRMaterialBase { this._coatRoughness; this._coatRoughnessTexture; this._coatIor; + this._coatDarkening; + this._coatDarkeningTexture; this._geometryNormalTexture; this._geometryCoatNormalTexture; this._geometryOpacity; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx index 93355c5585f..e8cfa1a6a2f 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrEnvironmentLighting.fx @@ -124,7 +124,7 @@ // This uses the geometric series for infinite reflections: // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² float effectiveReflectance = averageReflectance * coat_weight; - float transmission = (1.0 - effectiveReflectance) / (1.0 + effectiveReflectance); + float transmission = (1.0 - effectiveReflectance) * (1.0 - effectiveReflectance); coatAbsorption = coat_color * mix(1.0, transmission, coat_darkening); } diff --git a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx index a338a332dc3..5943c4fc620 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/openpbrIblFunctions.fx @@ -205,14 +205,10 @@ vec3 conductorIblFresnel(in ReflectanceParams reflectance, in float NdotV, in float roughness, in vec3 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. - return getF82Specular(NdotV, reflectance.coloredF0, reflectance.coloredF90, roughness); - + // This is an empirical hack to modify the F0 albedo based on roughness. It's not based on any paper + // or anything. Just trying to match results of rough metals in a pathtracer. + vec3 albedoF0 = mix(reflectance.coloredF0, pow(reflectance.coloredF0, vec3(1.4)), roughness); + return getF82Specular(NdotV, albedoF0, reflectance.coloredF90, roughness); #else return getReflectanceFromBRDFLookup(reflectance.coloredF0, reflectance.coloredF90, environmentBrdf); #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx index 1e04a59b1c5..b912f3c7a6c 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrEnvironmentLighting.fx @@ -126,7 +126,7 @@ // This uses the geometric series for infinite reflections: // T = (1-R) / (1 + R + R² + R³ + ...) = (1-R) / (1/(1-R)) = (1-R)² let effectiveReflectance = averageReflectance * coat_weight; - let transmission = (1.0f - effectiveReflectance) / (1.0f + effectiveReflectance); + let transmission = (1.0f - effectiveReflectance) * (1.0f - effectiveReflectance); coatAbsorption = coat_color * mix(1.0f, transmission, coat_darkening); } diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx index eb7b52edad8..3eb5c1b61f8 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/openpbrIblFunctions.fx @@ -196,13 +196,10 @@ fn conductorIblFresnel(reflectance: ReflectanceParams, NdotV: f32, roughness: f32, environmentBrdf: vec3f) -> vec3f { #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 reflectanceOut 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. - return getF82Specular(NdotV, reflectance.coloredF0, reflectance.coloredF90, roughness); + // This is an empirical hack to modify the F0 albedo based on roughness. It's not based on any paper + // or anything. Just trying to match results of rough metals in a pathtracer. + let albedoF0: vec3f = mix(reflectance.coloredF0, pow(reflectance.coloredF0, vec3f(1.4f)), roughness); + return getF82Specular(NdotV, albedoF0, reflectance.coloredF90, roughness); #else return getReflectanceFromBRDFLookup(reflectance.coloredF0, reflectance.coloredF90, environmentBrdf); #endif diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/openpbrMaterialPropertyGridComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/openpbrMaterialPropertyGridComponent.tsx index 22364f61551..6ef79c75fa3 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/openpbrMaterialPropertyGridComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/openpbrMaterialPropertyGridComponent.tsx @@ -450,6 +450,14 @@ export class OpenPBRMaterialPropertyGridComponent extends React.Component + 2*!W{dtQfKP7JC#`MPjzp9;NoCW{sk@*t@j07`19sRPESBQB+m!+Evuv z&*|s;JpaS@{1C6#5$D|Fy07`Z#A<7*l0fJoAP|V;k(!b&2!#C<1j0%IV*__?jAF-u zA6Q-1r8se=fuA9i1N1Uq5uDtWTs zDk?baxJK%s8kzN$K|l&s;nE8~m{d}dcS*{F*I*F9DrjV{V?@e5xXae^-*xb@==B*1?SI!VLJk!EzbpA(0+jyW zE!l4(NXP%a_OusV7zSKDHYEQaeksvpQOYuf&pgnxOt(USI)2XObPCPrl0irGe$~uo#fCPnBzQhfR7aL>y zn?Ypw!)vXZl9xBZ#gpZ;yXP?T>0O@*3@cc6+>3G0lX1S8X)sH(Y`>!=OP!2t2-#8}##vb(4L@UT$*tX2M7*-nO$MqXw>5p!DEuFc} zcZSH%UTI=UxgBSZ*>{-N&Nu_lFsa5CJUAD@2Oa!43tBo890@p|z$Gh#s(`g%<{>v? zlW6Fu(tla-Tk-nh{aJ^YonU|88do}^hewdZSOXh@$p5GePOaj>Ck*w)(kt?PWv zZb1I#m0TRVUkcAlHQECaq#ymkkLMZLW85;$pv+BRm2QGVUcI_n?T^=bc%t8AvK|sB zK_7I`L(t;B6nuWbHpGUC&EIUTc|LzS$nwlz*3j0p({yQZv1WF6c|p9H`5x$^!mx7v z1>NuLO@GVn@{{OgkX?5})y++sj$v1D$JDmBrJD9$S*||(jdK$OZ7e_yJ=Ufum-rep zchtVNW;3$0d6RAex+zX&(M+6~G03EEYipwsG7TNy-``*Qm%H)-v?s97FUh?wSX${aJ-Ru)!_!9WT~DUjciOGqy~Sr6oj71l0!% z?Vbdbt+mxW`{lR{NS;YG^@e-}OQ-_H`x)oTnahr)s}7digXow0i+N-A8l6<~WEP&8 zd%u6K zwo6BR=<)kGcH&90+6!KZ?IRL)@o6*5El(Ip{?fL8RkLgI*2mjhzd|37-#>rcst0bT zREsBjdV0KNPJ%+@(BcRjN0nC7;GK&1oBl0s_x)w-sd&RIi*>pWaL(!9F=b*|1dC<; z-rKV(Q0zsRh(xfcUR3GB+uFj`q+h+#Z5_iKm+vBs#j=+b;p`?VUU;SH0J(oE}y&YHYES?-DGxAye&`@ZKpvM#1U%}Y&; zk2BKH{lM0-M;=#ydiTVwW!~ko*%h6xFc*q>r=mq$W3g{}n#}id#VGS46VF+KzS{7) zon6WN9&lQMyOy@S=@Ws;_?o?x$s>*Koph9-Pb^RY`;e=phuMe1y1i3&KPhijygHpb zF|Q@4rxy-8K%T;SykkU!QJ{#JhxZ5wPIAHLu>2t3js-Ux1&t+L5e17r&{zgO!qWJg z?bngD?XK`Lw0Q{$LgPt#ED=MZO5+@=hHfb1ymQ~5`8dhS2g;4T#&c-l8Lq)ixwP~- zhcE&R9Guq&JC!tcW+7B|*xZOX3$_*CW z;%hI$$%4FXLA`$fAs?R~jf^Iufj@ZgV2fm;3Uu?iD50NGG)~D(b6q!IhO3Wvgz50E*vjex;N7X#M;j`aZGjbNH zXR$psSWYh$XB@KzG^b>a!4t(Iq zaO;uk$D?m|)qb(UnoL}6dVLrjWX#4g;~datWlj`Pkd@?vU`|}cY2AYEqJEUS^_^7%#9s77!WEOfR+x5A`4|Gu~vql2{R zBXksnHkN4p#3J8spYk`!o(GtRuiJ#d?-F357j6}H5vI)qTzuKet1)?LIetB&d zSu~L~9*_3GNYN)Y-FqeCSoWm9vex|9ldjIJBp#n^E(wvq=g*s6=bacjdGenco0+ZK zSSx>)LR3r@7MWE0${0Jc2_-HwarnTcB@8ujMd0*_z3pO~_}L=Jr;hEnmv$QGbY*Gokf`0)Z)A}f`tdWml1T$Mh4bH`f>*tl$C zb3;RTzm5;<$97DAX^B3(X&z_RXY)v$Pv>x2FGz!IYdlG9Zkem1+fMD|GRz6hCzb%E zrUFdRx7pc3UbR})xINqV)Q_+)TKx2|@7J5VzaG$qZ;|%nqiMqmzO;?tgoFS)*p$TN z@Q?&<`OvXl!6Qpr7#~)5`}OQ>Y61g@dgL+4JoN(C*+JBkOd-noBy7`vW~aZeLgXp4 z3OGKdEPrQ>)T*JAmd)c^WDPF3IuLxd%8NP~>Z7zS2uIeUTPf+@wm4olMmOjPWl(Cx zh{8X%;|dKY1b|nV3@c~)t=;RTb68>J;TX3aD}%JIXpi&pvk;;_qbo_^#{A3 z;Si&iDNhwbAGiTttJRw-1#f|A|@qqBqOOnBRoMEZWpA)h|GFme<%jEkS)J4#Y+ zrN8<+>{d1v%LLlywRZeiWv^)eckBHd=aU|n=0;9fomwuwf^#%$J|jdNg5l40nF!N? zzp-z8Fv5fH{&R~^y&rRpBED|qcU&pV7jqWu+nXbX;Blb(F=IKKqSUw|%?9;_^qTUf zOjT22p~ALTc3>mDq2El4i+_8dGPvy}lqNOWUgOun#wLNCNyc@d6hCVUU(=eYk;F=hN=Hcu~6|V^b(84xV4M!iJn~ z**DxsJQO(wdu7)`Ufm$&G3zMHPgcmwJ_Q({`4P||;@nT>>^Z+adZq^iiQckNAwTxo zg|odw@*3^Pfmb#ai+i>0GbyuCx!QwhH;W?j61B-a-wMcIigGtH^3HF8wm!ay0i5E< zX`XWZRf5R2wkP2DNID(Jh94jJhW`!ZPjMwJrx@yMk$HrAnfSGo*;%8#mlQJ$KeiWa zrE_q7l=Gc-m{WOsW7aR7K8EDa<}ZKd#64REO%<53Onp{jsoxUI9@8-%;5GQo)zO%L z56|my!qYzlV-Ax1uWdzX!Ww#hyBk&X5kt_g+#(3$XBr0U5EYiU#>2W;ixekW2ROjc z3@eW=XihHI%Vk|$FRH)2uTxDg8VxJeP$0huj3s50jfN;w{Tb{dBc8wgu+T~U1`;7* ziK>Hs3}}j66oP>QuAfvJM(j1t?@8v8Dzxp_(xF^EE5en9Lk(A~n@j{V_6^}QN?HQ_dRiwJ#E5d1Zk+wc zLkX)#qPpPG@7;IgE}b~~ec&kI#78C~!76Sm{NjA9c1RYz^C5_mwW41pAt`Zzwb(`Z ze2^Fg4Bx36Y{gdh>C@w9Y~_$u`wP}Ek3gl`+2<|uCA!0&xx=<%jHK!%6fTqkReg?M z%m>Pc#fm`E%_-TkA6_0^Fjkwl2G*L&)oMk4l6q~fdH^r4A^q$)IgAT=z_Ep;a$Y$R z6gEEX+%zYE6!BhvjKhR&<)m!}o6?bHBTOBASQ36nCIUy2#U??XP=JhTn^8}u11}h* zG6!912fKwW|$jh!&dk z0BG)y>FbatEY!8OU01^+Aa4Z*yVaHMdU3;`?XBNpGyv(zf{vMF-kNU&D`M#Va7 zsNz1kSn)E7j+2+~LdU?upD@ZCSSnk>*d=miawj23-LUjnCdP{bTE} zociH%sG;r5waABpSv3Ou>-Upe5y5wSH(^#O_zBRB1h37<(}$Y|Pyw~dnVpk>`T2Rk zb=8tRRBE|e#}{H?U^u$?*-&-pmoV?fCh;Vv?kG{zwE;uRtV(c?7EF+3QNstCt!X-( zu(X22li`N3RN-)C{-$Wg5LH-qM!puTqNVIlH8JkloqeG3v?@ixgdxJ+Df5d$8udNY zVZF!qZhvzTkxYxCEEsOI0`;0$Qv{%l_k6EzZh!nRDVyTU81eYIVO<~kQ3QyW+bA6{;L#%9jo+LHUVt~Yv$HeT=um6X zwYcqlFvw;c_v(qVpiQ};oXrN+3ve|3k7g3p+ppvD0W}9z%b!2TxsYL5kwW#X)?Z}B zdA2)dwpc(UQI%UMaTkGqq%~VjqbMy>qx-GH9@j=$_ekGmZ)-=^;n*BcY$nQBqJAAH z=^#s|oZ1#j(bEaZ!lvcjgXacN4Sr+5wn@+fVT#C;FZmDW_s<*}=O!m7t?NA)2b*1Y zo`G4=Ul}5}jDO^kQj8y+lb76w6Mv1kAovx#u)sYM0;qE8kxHMF;f`MqrMh=Js%=}ZX(zJZHsk6ay!;hZGb0+4DZP<#14RO3b z{OX{XM^$2n1j{`xdA;eMry1SKHFEiJsQs7&a?dwsjvs}U_bcUe zMP58h!)5+dmW*tg+PM%(Z)eB65r+f?E)7Ead=@4he@T;iEq1tuyf47EVfE1>Pz1Ka zt;qx$0bxnJi)?V9`9waN1`lVxq)%Y#ZV-4JxqsC-=OTNnJV9fAhF& z>8?@!O1w#``}#fYa&)wSknQ&a+3^N}Sszb*OI+c;NFtaO@n8!{uLL5*Gbkv?!J%w+ z7tntz@;WL>2eqh%9+6%iLSBY*@2PDneEbARY2+ZQO=gUURIa>*y=1D@!OWW>m>Nh7 zJ-4(Ja(=MlCtGR~Q}eR?oNz{SZ%uECEQIK-hlrG9mc~Rj%KBx78L!~;o9+QMmtmY* z7Lv-*qW&!gih)5HEa;JYxFz^g;EMgu->r{J`;|7Va;gwCdVI5Y<=`yj?(E@salKKy z0au*kQx)(yaa2UiMW9@k25TibJt5&yFXjRxkQ>^y>c1F4K!zXDV=Ly#NMH&rWE9fV z)_#SbPB)s($~ahvbK4Vv{{6e1mw^_)0t2>k+wyILz}|^dI!qoO9$sF`WKQc=90Nhp zvlh39f#)6)^oNMTDgs^mFX!%bIMH2MItY4@&eOM%U66eJZ!8FL%k$q2?vpN7!uTJM z2k{rjiFpE*qdDTY_tMyX8KXlK#*Z?Uxf?=c7PM4Tc}wxB-0)j8?WkV}MEIe!C0Uh6 z$%yB0*nNHNF=Jd*MwYS~WmCPqinOr7!9gH|?p=X85Oh4dSt(>y9iSEW1YO${NxXj& zhWH_Z%w#zC(EiRD4wq(5K07!u{bG%4j7AS6*o$>kJXp=qU5FRNaJSEjrVIU{v@D zRCT+F*7J4(>0&_Cqp$&?lp1Wj4K!07{H22i&86TChR(U*yDYya!w)NM5CQ-m1W2azLMSbyX-eB>xr=eJ-Kyn%&vPYO$)_$l+=72Xul-olr!I@hGN z5AE0sgO}hLMkrs4`fQQZ+YBxy4*T4p&jYgDX@q7EP|{ve3j!JbPi2fP6J--r)Ltuw zW5EX(Im(}-4r!<8n7gCc4M3qYOdF`ucEEPCbepcvPEKu;P%<0gb?Xz%bu$M|$p47q z$=!qqPS>A{W6QM60KxHFyRc!K(#uvat`)JzS=%(hGcBgq&#k7Q?!O&R-;{AlP`?A6 zq05S9cSY9~eWZu@SO4;>&<6WS(!S*-J8qI=UVxFYPb*&tKl_Md0=|jOs`0LKU$)DBxl0HMrVF8Z-Aq9;=m)Xj#qsRvX%s zYgh3ma)yb5$v;PEa%o7)9zW#tSffR=ey|)Rh}^0Wnco$8iTQc7AS&aez+AKY z&G}w7#dION{+)HzS)B87=9};Yi1Vjws;TXCa^zU&+&l2(N?cN!wmjin%nsX=GCdQ< zg&%)M)@#3W^|LeP@?~s+1o9>C46txlrv&i_i{-(N;44ux3j3?8GkVagTVV7-gXi5Ag zrNZ{v(fHl|8-Dln$0d7v1*UF<@^ld?espWJhn~7F+D*%6BL=fXS!oaKf)p`}EMua* zlqL6()_!XBJQ+P=B29Bu^__nviV=}PEZz;1(xV}`qcLJ9WQ+F7a1t@`tQK$W+exj! zL)zrQOyzeE$;Dn#6;qejIqIlKAic)Vud;LS4?_30mhb&ij`Yn<{j^R<{+dId=!sXd zF#CEmALHP~L2pRt?Dck=j241G5Y1P3gf!fY-xDOXS^w_hmwz_Qb4Qh|67gMx-0E9* zb;*S}h&fKkzwk~dkS%Ap!IlP1sw^6X-_Av+fX-m<<_~mM{#i^%9`&BpoyF(UzFvrS z{un1k<5QD_EAgXyjQZ*Lk<=DyVA5o+xo)%_q@7oehMN z%ASk^Wz6Ai;dBCC^>06h6wen{Le5kn3qT-rVgkJQF!o&Es*l#h6)xbi*6&d1Z48yf2wLJ5)lJEC8HzIx zo;1Rvp}0S6dF_tnCGo%3#6O7Cv;MYxO$Doahm!l45VzjjgWKj%v0zc^9~bs1utp8_ zo+n<$wdN7Hlb?a@JLWAF1AbPI66$_vR#ECIG9b^K%A{T!XVBJ%mLZx%jL<};Z)ZpU zbh+^D!|AEbwVd)SAv}g*6PaI<=@2H~%-HJi(YNo@6W8Y>c^8AuqSYc((#qGh0wS|$ zuG@&&FfAyrXgcOc^;Rid8cLaD?0ZEN75utg#HCN~p8g{1@M9qO;~LhOiW9AwKO7WJmnkJl zY4CJ=o9%-yl->RfrB2JNPhFI+gC`SU<&I z#TaASM66?>N3kUZkG;elKN5nLV9oQL{- zlo&s1ivj%KW*P4njPwf8BD2D5gG0IE@XX&x`dfcHea?LTr1#;0m$;t^c8;P+G;#ku zEjRc(Pf_!2;n>pUL$PaeWP2kz5weO!pD?^8m{*$kY+#jNf8y*$e@{-At?~BqjZJ{^ zciM{a*dl-Up3D88uU)1P{RdAwCCc~ZFj*m*SKOVoQ zBvsMv5!jPc#Jj|GhQIYB@^0w!uV8f%YHVm=|8Oh%KH^Ypvq7?SK~YxOtyNh0?u zV|k=@Y52Ba&AlO_f3o=TuAN%Q{p_St&f9RaBwRw;P@DV#)=(oNSg-(xd1r;vVqE~q%?f8A|=!k|^#pvicxsBrufZ6BdiyQPaRYcb1XF?X5SK=5 zwW%9w_+SuotYIrwVnt;zV1!Y-pMW}^ZiPssD3c(unJ}Wu;MHZTl05h+_xe?EhdF^w znNY_2Hue+oqByaqNpNtgHc-@xSo1rqPe@Z^QiNXG{)8C|p@H@E(5Jg|`)xou@*$Qz z0g`VGcoFnTjf>lUmir>?rreAP^^&X>Fr@;mf&zButztcV%7#=M+tDjrSy;9S?GAj~ zBYcpwY=McR&qWdk4Ptv|eW6sZ8KEKMgJ{f_d-cyL*}9$bugU+e?hB&U##1kOz3)C| zFPYo_`B)Xqfy_Ih5d9hc(*R29=pvb;@jkbZz2`+m3gzRNHEFt9O4VH!Ttu~D?{emL zcI*#fdSU-BXEE6);bjaeU@wp>Md7nY%8&OC@HJD(*ZHklD_KE*Am+QOD0QK?1rH*A zjo_Qy^{@VRkql2~Wx+3*R^}R|*p!o$9jC+}tncliz2{>>Gs-U}IYa?GF4T2?`3TdZ zkp}+aVZ|k2p2JH?w9%#~H+KE8hN!3hpgc_NTjEQia;<`)80tQrgCH~wGPHD(Y%f}$ zCYcDM(iGq+`CyrH19YQFck?vGoks=v!l9Ry;ollG&S^puL>b@xk(aMjLT=5M**#Q6t;h*4H(Xh*h#FRP0*B_jxe)HbtS?h!7#bA#FuC~sIgF`3+&>- zy>AL-gkRdR&m?mQ(rKIoBA7(9dS_^5R8~1iXji{L2lF^n`r$su?Rv)O0j) zi7IQ4p+9Nf5-J`Q?UdY;@j-ZfyS4#ype_nb<@T?l9d9D-kXcz%`vg5tl$ZwjTzW$4 zrFXBQEpME(hjQ-c3Dp1C+H6oWWm%>aN!2E1BVK=}9p4u@35# z(p%lp_J51~f#c=oVb-Es(XC%LdoM4jKhR#+{6dI$0_$mqN%a5~$`(n>CvE??x7l?> z()$YqGHuq;^zi1@GP6}nj0w2-1%@~o)2#HPIZ-amBQ4C2ts#Lj)R_D5`@dk8H)H(j z7RUQ;g*|UY=EyjYe5?bOA2zy@r@{R(JH_HDpM+Q3mTJ9PyS58><&)4pr4j{3TT@d> z{nyUURP&8fh5mcPN@5sbGU#~v`5@UIBC3EqP-j=lfA1p|w#bMj8yC;5dZ+2wUq`YU@Ai|NI0Tu^R)5Ft( zFg$-go-oKFCWnQTmSp!=-=d@nBcUYSAmTvX$1&A0)hC61*_nuv`ays`ynQ-?qiYr4 zk0hrW5V-^#>N9o$rKhe*f`4b*)y6`b zd^pZ4pP$$}lvMYj35fpw_}WF_v56{*JiNaKRVI-vO2qIl=q~@WKgpSdNXmB&C+QLf z`Nv+gxy(R85#sA>-X3x{IDO+_T|k-o_c89jg}plMn!>FZJ)Tmi8!FUt8N6HVH|jcH zU9xrZVq@??nOn_A+32lEYj&7#X6TmZaawY;&TCO{GYXIbMJMp)myST-ZRc|2R(ZvB zZ%OM%WxKq$o5tm?jG&;8?A}BW=1b1-L%(*wK##!0UCuj0K8xYT@Z_Hl46@wWG?~m8 zKiBsllz=~#NFTc^c06B=53#|p4t#~(KSpqh)yQ4^LQm`*y5v$3n&!u$@2>AGYcieL z3=rUW%1`V1DMKmeK$Nu1A36G+_aiPnOn?;_6*)Tiay(&sFbMOv^PV85bh+I5@_tqU z^uco4C1nLWA3XSS>MoIAVEcP$n9c`gC^I2xti|=JJD{O7(pJaGZC(%o3JtFxaQ~S! z{!-c=W5p(yqi>HxdLOOF_p^h;S2t1Q!@7ryuR;=o`nRB*=T}pTtBR{U@)sdi8NLY# z@ww1ak<;c(ptfq-e)Wg!s55d%%}JUL4vHc`6=GNsbp%0lR0KS3Ki<9Ujf&F`aSaer z#P(cuJFgFq1;;0)tzOuRq-f&8<}`Q}@s^biEcNTofdW0Y_Q72KI#f)bl^6zAjO=+0 z+_Tmmoy#9N7u5$5ll{9V_OFny{b4SDZJCb>cA?3xh*zL3`%4Z^%-#cD8CE3c4n#yf z`J+#TB2dI*f5{xD7#Sv)0L|C`b#H}8+L9Os>czomTR{l{`bV-M_W+Lt9t8tTAfiXVU%hSA27HkPFw0?Oqd*edRad?io`ZywhU6VV50%8=m$@ms#V zQr>Bqk4T?LNE8HBi0xtGFCv0G|F}HA6b$Ij$)o2Uvm0GkZD&WFZ5oH4`DxA@iI$hc z&lcxLuKtMij|ihFnS<$Yd&Yx(Gk2@)5{)c6)G7+1pWPgn5wtF5BdCGd${gnH%NkYA zC|vI(PyC}P@N<3RH%)-_l3e(vf6eaglzhGMca~8&YpO&BnFlVA&@s z2Qx;(Vmu3a0@B@VEq+@w1S|=EKkn)uT<&IAIcs;b7Dhi~vrj&t{RB=X1g68>e)MH( z^cY}+03U6}*{5w`W@aWaF>!2c4ES_wc_x%mHnk0;Mge%GH<~OtIXSww(9XEoHG&-* z2)fJ{lVJo)=L3`;*5nU+V4$V1@qShJLz%skco6xf%7MGpm3~FSN6W|024DpyL)wQU z7NlMQ=_Loi%Iutc^6>SR$i|!|rshIsu{UpEne+hk^nGDr zVR12PJXxg}P!hl6g*(45Ey>Ht-3RWA(f3~B)TJq_SqiGmaBUab) zUgih?9d0ZSxBRipui-a=0aoGDr+|&oEc05P>xaN*mwKc3fI@gyigBo&8yO zAR|McJh*&qZH9tdx0)_4x>eWCl93T{;_!wY)cG-~hn@@SfsTSg#IoAY7GKfcVmPKI zRLgPKU-&<-Z0$6EAoKS{fTO53b_IXIGL|*{_|fgD``sxpBg|c!3HiwS-^+lGrCMTq zysx1~=B*ynn)j$iROzt}{FoX$DCdi4rQDrTbQfGZBa zym?$}M4w1)CFQ6sojJWl*elg_!I>^&%f%uy({m9i0PTwe%#&llVPHW7K>R)U_1 zh2>xQ!BT`dnN2v(huoRYNybq!XFZ?pYC{T*YePV$>H6@V?zD-h6^Xg+;|S!G)(MVY zDFXWQ)4J`|Pwe)a(|a+mwv_V;RLHZ)#0jld8i~Tzdmp@f@wS)7;-^!~JZ3IT4~MI6 z(otcrV8IO#MU!en_?vK64*&=P4wIe$^y`QF7V7pyaE)+yz`!#q=_etv6-{6MM7J@gkzi#B;yZQMsy zJ<_11adn)3(*L1fYz=Xq0P&d)@xX&M&W-vkM3X&l)jk9e#X7~ur*z(w+rPV4Wney? zcKW3u7&cM#cp`N^D=nKWU8sV#<0Ty%>MLG*DHc24w?vN(o0rnTk-Gq$BflblCp$&V zh8vFg&Eno*w*=|e-6YtCIYS*9jZaO$VXS5haLO*f+LJD2xFze}zLA8RylCLfu0zgP zsf({jtyA3)Zqm7c>@*<`WWZQf*2VTwBtrJrS{t1brlsqK3P1e%=eI{7$Wi%Dme!`Y z&F`(265Z{uB|rA&5tkC_1?(}U=-OBPU^j1Ets5+bR#Ulu^@-I! zHA@$R__7dLOMn_2ZCJsYRsHC~VTKo>U9UgTs3Y^5C%A4qrn4a7=p(J6BDnoa{L>T~Jl^oYRqI z9VhTQ8ut#LH=;K?PF0cyGOIn$^OJ~(g}>yRy)&ZnzuJ4ALYHKFrnqEsD-%Knpl4oF z>cVWN8#!%I5MTMk=o$A_#P!LG*7i>_Or%D-McDdKbMbAgy!%D@(lYMbAq`6{8%Gzm z?B-pzDGz{`Q2{S&nsn5DMWC(qcilmNOohn*D9qxe?_(#HFhe_WXF@Yk-I)9Y2ffOfJ2w5c(jW?5yd zo>iUfKli5~+&iDh0_;$1|A>S9KsjS<4Aq9S7<@%f5_-(!e=C=EnYrq~#}-SV=-$~% zgrz;Lpndr5^=;TC!6Em9yi~gr%6HfX+Tu`C-I=#6w0`Kl)9&V3igy@Ra=?pZ{I>yw zq31Es?tR+uDXs4-)CM$)^5aBSt)`lF?0>&KGeY3ey~;>zt^i~?QbsA&Qsj7m!3b3< zfBa}F#_yN_KTt4Zgb>mV@N4?V{RdJh%OWv@gyK)=6BWnjHBgXLB1*Tbvi;ObfBjoeNO(t5lw07%<+f5be=N&rla zx_~D?`2)y1hgTo5^*FS3kcC^pp>#Am`gCYWDcyw8o}<$3WxK}nZvI-+0=U{8W3rty z>X6y=JiFy(UAWiqXDH*FXsh~F&$qRtLXYATNEl)2_=-~Q`9@MPJ7pRuDVEQ%NQ5HO zlc>1woV4$N^cx;#-rXXtg0=A_{elv?QC}|)o6I}@z3D~KygN)}Zy^!<{0fz0%1v8D z8Wt?7ky@EPC*1Fzvd39a5Yuw2p!~aU8E}yz*0EA|!gu(Q$jmPOHPvX6m0D%EHAyr@ zRW^ z@7CEs()S~|IdoT)e6`U?BF_hd{nk3whHH5LMvw}cBx|_WMravT z{2d$Q|DrHpTf0ZL_#lHfM%RO#fdP~E*%Ks89seI?M)@YXHpn$+n~Cymc~%u+nphaw zsJ*zH?z^t6uJZe`5@m#i|KV=%|HXg)!KhA(tl{@%NRugCC37YWA%lhYlWgWCucd#- zbN{YO){&q3=@z#r!hFP}1X?FU>3Td6iQsB7{3X_HGUzA^q+BL3mR6*Qzrx)<#$rTPdCOt?1Znkx zb`aly37o_SgLMS8qC=;qp<=`mkAGOAVa8chn_+P!|3LYhaL; z5s(<&?f8J325K7o3LpXW#c#Vre7QwzHtQWPqeNGIz31U-Kj23a(Fk=9y3E(iIR7Ka zBY9FW&vYCF1 z!uUNr$QD7F!J|oUA9Ia0KqaEU>g_u}XxpQHe#CfGK8kthm-&<~NwkohO&crZlSzkO zwK;JKGLvnYh0z+3$=zY@?&H%mzh?-C&HAVo>i`rGd-&=#HJ;8$TErB$pPJ)a?{2;dKari33&&o{r^e16?LzjtzSa&r?TYYh!y$ZNT5G_qff zT!5ZqsXYV)RHYcpsQg6u&EqB$KVvmooQg4)d>#V(j8uh+rVSYG;uwR?`^95RP z4Z;bhuWl^>SM}w~7l4VH{r2ti`d>>C058nnoNE@$WtI8RSI&CSk32||9j`R3lvX{E z%E5K&1d=s8<^kKpXev8RN+lzJF9Z5QbYQs4i~MmuVZbb?L454U(EY1s*V)|@AO=|6 zi7drrZunX8fyLDi=ow<@6M=kpT`1@4b;wO-09)$>4@i?c?NNpPj^_4K?PqK z6Pm>k8m@?EeQ4iE$V@0yrZY{nCfX~^XdB>ov0`QXc1;?BQRU}$Ja3wODi z0#aJePif!9YK)IdScZy1#g`6ncu`O)-?s3ZPyaPrbnYK1w`mWVES})7jwT`L2F`9) zJRIjGy}k!QapU_R;=w-5rnksp=-E=H93_GeB3Qs7aOP>I0~t94G|*qB*v>d@7`GfG z$;|XB_}M^j<9LnDR96br_@>rW2-q0;yCeCsld|;gL7BiGp!=R?G}M9#Djb8JDG*CV zQOOAT;6*U%cBE5)(;GL)g`4i3o^0VX;tU+XNSd@h{#oO#(!v zf=EOpK){e&x%sU`3YPYeb@ta@lOJ6RdzzgA_=_y_eDj_^GqVtju#CQRBa$IHbUQIq zgL~pWa_lkCKcd#WcKc(t^LI%)tUEIX+Vy4AYt|6!1W)FeJwQC| zGyVn|92}URP*eS_bVSuwNQD~7j$cK{p94g=5A8DDw-tmZki#=*0|?HXu^)RDuF4Pc zf*TtCqEaBi?gjxZqwoEzN)^L#z1IO(62N)5qO<5_sGNdduc%6EvOZ^LpauM}|1eQq zSpj0*D00ltZpM<*?>>YZulKLghWi?-G&e_FWzA-9&exL9PEYY8u=*mQZU-bcg=y$R zTe>OX51!{h1IWQ8P+|9EbO89YO01uICVLcjp$&PswsShaaOXvrB^?zQ=i~TlP$~ln z^@>2G?AD^L9#F$S1Tk;>MryV@Rwm>5ps?Q>i_cowE%cVv%M20k!CIjTCL!Q+na>}y zmyWXQy{#y_Y$$ts111KhAKkmMH{Y_q)Fn?#420Y-0|SXohCapyUP!{H$7W<)fIW7+ z8!)y^A^OMnIOH1_bCZqOc)wn24^J6ssEUY)aBlk4*=b%o3nUnT?84&WKXOZ@m|O`p zy*FcwO>SbW|D0`zY`PZ(Fs7B2T|bOVO@)q9p`18bysAw2hYVXH{NJsgNm+%*za*l1 zq@zZD1nhFcJ$K2u@ed|~S&9mD%T3TT+SR)^8u3p!nQh&5@?maRAMLL76s|P7?$%FV z6;Be}-0F=woQo>hSOjL2K8*MmMM*OPsQRSiho=GpBQkPw8b zRD})@r@OitzqK=Nz+mApy`{oYREZaO9v)gj68|t@19~O<4-Y!9PkP&#=>e70i7+^- zGxw-}s*te(oG@30Y`uaj1#w|`<=)X$j?|@hz=I^p%ev)vYt;8O%B0s8Dw|RWAx>`E zR_zB;LkZaeO7?-+c!D3DkxwG+j2&<2&h9QxNbjBPAS+gt!?mRbqZ$fJvD0;VQGtc& zPUr792#{8$DujspRpp04EHZD-=TfQekHQKef0ezNdsjS$pA3_{4I{@edaS7=$2$4- zMn|hDydW&4=2R0U!xztOUa^wqokm*e^1jb1HWpUaO$Wkl1-5syg;YvC1X!3iIHR+) z_UebC1BQR&hB8|xKrz;0S>OtVUE!Z>TIa}x%S_Adcp9=fRs?MNFokgt3(hQeUAwne zyW(Rt6WXa>+pQ6{&i-+P^$!QmRpq3{qjyPgV@UezZen6NSIx6NBcNN(xhcT=_$V=P z6DjZV&*|I%Ib&r>>d37kp5cFv4&o|T`JO(m;ZvxyR#u5TpepH^kYG)obj1CJmV{W> zb|v5z{w92K_xfQl=B@l=Zo5z|^4;%2kMUga6okdrt!~SZ6;Gp}#K?YM%CR!4L#BZ8h3R9hW0;Hvz(Oo(Ub80Vm`GAG6FsZotu8z-*f{1 z_@1>`p3a1*X;*UZs3SOUqblaU@H9s4i(F#xal920P*unNsgP31QkF|cNFnkR<%3`= z8Qporsnn(Y*;1O39kyfeuHi)i5}ZLuF!MxF42G)5%B$BA&C&pJeikoZF7-L+^Tb7t z^~%~nPISFf_=KWfAicydAL&3w8vZQ2I=jBe0bt`8p!?StCqA&DI0Gb>^~<3``;KaR zVuGGlzP_R)B2nF1UhW#-G4q{6QspcuhUxDc5hk{2eMD2(8X@6c>};3-g>?ZPcz_bA zEU&f&w)%Z5=F&Yb_Fx{3L&A6IFm78)M-TV-Ef32tOv~XbZzan`1j-k#F+kl7J=-(QzPo zr0cI^6`zvA?h`@G98H%40as;BiBCrhL`nZLcsGhP@ONe1l?;;BdE1tx=z249d%||^W6;%-`(k^A zmU8$?L6M%sSMZ}068m_r$miwTyh=JfaX2~oB#Fg<0%Bl+W;mZf!RYWCV}Ij3 zi-+i})((veRj^#jYp##%>&iX?dF;}L^Ec_=Lp4nzPiCFcVtW#jXkapGDJgx8{;98v zvOjETvt1j?JETxB;5z}mE&1TF$SC`6WM$|fy=~@}L)Kd;8^Cps=ikf-8H?G!-XS0~ z=qY#M+}iIYB|NUMYpdRIh*iwesbmfE&1Vc2e4?9}wBL32a&!C+e+k^1LOE=#Pstu1 zYv+b_lj)HnU?C|v1k}I1K$@B>&jOW2KHw>IwHHdB1zzEp$V5gnllg%kRO2iE#d#|b zQE}huTZssX*iOVTJJ!q3)NYMs!z!HrWZ)XqOGtUs_f(M&=k)1cKI;H8=_lUY@l{o< z4DjsxI5LuN1=8t%0Ub>DL1lKbSm1je?F^N4L}I=y&hmBf&jR$f&f?! z*zG0iBPy171QXd$1Hq)9L>^rqn`BNa&p3r@%iD2>mwzXa9$0V z?FJ=^I+=rnqP={IkG@F=9IZf?Yx?iFNDF4g*T1rrNbJ%`#f_tN`wq%VCCCUR=;oxZXDE78-7WNcOZ+-WZ_O^i>S zA0GLGv($_LeJY;lNRLQGIk8Vkbdl;nZt zOv6f1KFZIEx?I0#OAy@D68{TQE!!4YJns05@DUuVobs|@L92~o0LLwsFbQ_(88F7$4zV{TBnk&%5GRa} zIQZUwq0oa#@Tlj?{o9cI%^Bx=LlL6np{4GXbFhlF-f!kHKU}?KRFrMhus!rJ z3@}J{Dk0q<5<`jz1B}w$NJ~n?5Yh+=h%`tGVj$fq9Ri|~l1g`eC-?I{Yklv_4}Y-6 zi@EBIy^nqD{IGd)bot~SyWqAkn%801>sClz2@50u8=hb@WEqyNV9&_f6#qCvuzdX^ zNYpU2Y8Ob!UsYb}-J@@Pj#MhHk| zdUfzd&j=JC9H?V8HD$KG{Sk$iA7FIL*kBY2`QA;l$y_Sok)fWx>Q@J@XYS+@y(;+w zZ$gp$n!~V}ZPKvsb6yfZoHJJl52hx;_ls!zuq5fn$hmwj%Q29Q`-qdfR7ptAz~e<6 zaSh1SGR*riL0NGkn#P^tCPbh4dG$c-S9*>EbCKT_GacQGam5h|h}=W!viX;XR#~

X-aQy;r-1NQ!3K!fXtk;vSq70wTYyR37_EqHI9LNa# z3sgE3$~bToqYtxcekkZjA~-Qf-5sWkQgBNQ!EM%{>D$^g3b07D=XVl(EY!_uF8lV2 zoqUw)(PhUw`ShEe4$j=M(7%pi+@%>wFFlUe(lOqSbd~9QcA_d`XWCY641w6)%YMIY zn`Fa;S#@QoYC`8C-_uPP(;#pa6aqjQf2mfrhN?S!I3&A*!+6HQ?d)c$4%H14!U*c{ zuGPD24bC-o5G9XTevp^4rc8ZJHk>8$RshZHw*SiSK{xdR$E4%qbP>H`6)TE~jL8%~Keamo zZ>Yi9u@#z1hn#{vlxH@AU)67KJVGpvAV$q;1z_ef#Wv5E%(yS?><_?pCrRbHL zz{1WiN}{Qm_uWZJ5*Mpkan5i9P$db_h$W@Uur9#N-K=@Y_fIoed_w}+qEQd29an_! zp`S22M)};JV&@u<)OzNoG$2$TxwtUSvz1SXDzEn(p4FFPKUY&WSG><5owfPpl3Q0+ z9{L&egb`iB;=+@9wNz%_-WFhi5wru?Pu0|idkG(Wgy)`o(a%TO2*R@bw(4C9M(3BT zESQz-w-qhEndhND%}&W|KXWP^bKn73>!{Nyp|oDpujUoWTETl|G&IS^w>QYs5BKoF zT3q$>^U>pNd5+GC{BfV7Q`wW0uUDm}Eq~8z7nZTS-b?B*2Pk~+Rt~c<_)p8i_sO2; z8x{0d81gnm%!*}rpDH$@B2ZL^Fv9|;f3@_!8E(3ppbxkX%%Du2gW*MN9R~g1tr0Ah;}|Toc@>R2*0|IA9Yl9}$G=#f0zhdC~4p z^cm;;eMm!jQyN5tUEOSIajEz$MEN14TM>|4pvvv_-Gok+t;-}CwhS2rM3xKvv26-3 zlz8^b$2lG2P&G8zFW8HQz-IQ;8HaQ2Lvt0}ZwM#*+A4$ZJvF%~$qx>+6)0{2d~L?x zrrY??kZLWZlz8mOE+KP+Ck?-zNFXBaK!|9dDvY=8-4l@Y-AOqO(7X$kM)o4GL(TKv zDwC7^M>U0MuAcc`u)1EJ%8;h)@p!P%xMt6O`Q;=I%BjW2%lH_{si^r7xShF+KkL$t zkA6QDrQ0yxT|%6J0<^C!*E#xfPjDkN0^&seP)Oqb7fJX4iH*)k&8@!mWIBe0?MO!M z*-Fv*ac~@=&Q~r`Z&57$<@*Yjy6#7Rr?!9j*FGs<82aSMN!Sy)>euBIX>5!B*>KE1 zCx!zbp?WHd@MI{S_gAM`2ACWkvdU*^XUFbByGi3;@qC^Zo21Xyp9Y`cP7bwFgs{_F z^(crNz_(^=ud{Smt#E!7=)Pu^KWVOl!f08Qj!V+VJ2BxA$e9bd7<{g%)~9)}>}W6Z z7jfmoa@Q^TRQaZIUPrOKp@csgjB2m&N+CP43dy$xxp`zS4{|I5o!S~ww-iZJ4h|!$v%V(Qx5JMMUX6m-TXjtfh-C>i# z;%eRp@n;@c(nuIg5wCT6`bG-VC!cKR->uk-!V;7LbQAu=b|8vTz_RlP+LzNmb3<3# zR7o+7E6I7-D0wEpGT&s#Ex3j-!-2~*|BF>I0YFD>`QAdTh^>c2z<<0Eih&7!V1d~w zT_|n{twc`B}3Y=AKrlmO=sP^o8#XJXCp4;u z0UTK_Xw~O8SK2q<82bCaNlCw4nq62A5&wDX&D_@56J)5A!y0vRGZtw`80#fa_ox!KL5i-L6+F`-1l%lB#Yc^V(_6+Z{xb^N9DutNWmobk7G1prhj`rZExK&cia-vCe@dA|j(udlX&52}xCsWxa+ zneJrKD}dN_w3o)|{W^Xy^a(T33{!`DBD&->uFKz5EiaXa|h_Ov{AKLFTw=C)m(olWXJ z*FnmqeGbqja%XD=4L;jUOiVz+v+fy_!W_5|e3}LXKn9`##|;7_&z@#naAKd9-YBw& zJwn{7`DCh4MC;sNyV64EE(TXKo;|gZfl$6u$Mb8w{)!?gWjkxW-p^tFvl~DrFOq}U zZ);&H?mjv?>WZcI@$vC*V!8lf$Xb_QXN$1{;MWNW37}4~m(`Iq5wL|U+XQ0zu+NRI ztt@wf&TGxOX*DmOm*JK~gXwQoDiI*LAak+qxgnXbS=$Llv@ss1aumP zmt}Tg9(dmY<>KV(dcC!MwPkkEW!Adhqha2O!*zK!H9WMspL4OSpqW_S4xWgx0m}IZ z;A(nYKIz?X85MjI6?_Svz9r^s8Z?TGZfp)!K56P}0i0i#i_|@|vibb!PJ;V$Q4dD9 zkA1wo-11*|47(;%mj|25CLR1TCB9a>>e9M|r$($V;Mk>d!da%YD zv?P&TB!X==V*LOp06e7uZv?Qn)#02L-(9xnF`!QP=2`-;6#(==RQ|up=M6lKuLB&U z^UvLV1xIcutjM{me`yYZv3_ZN2}l@pC7^1`2>h6t%}oRR;C#^bnQV^HYcU!)2`MQ6 zp6xRbkCVud(x=y(Elew&ZD}XJk4^J~>Z{j5aq=!-mXF+)SwOE#B zMjhnZ#Sm@VP1=02oZ=89N}~j_AmriOf!nub&ytH8s~NC8qQ{$oS1NPxd6Q}7lMn6_ zUz}ITa(z-WP8(s^K<~xxp@yT7x97l>fS$_%{d0B)%Vv`IC z)OSx{JZyE;GNd_yE4JM@ys^vAaD?rWGZ+IdNeLR=V7(kk77(+!X2$;@B``E&wKAC7 zTeA}()-iS-ssrdm>C=VdfP+yE9Hy(;;PW@Uh*VmeF1raiCL{csQAj;Ma@GAHhmD&F z06AIrKEg{v2CSQ7n@JA)^3C2xF4sPQV@bM3US^wSc6005}YR zw+u~;oYKLh8AXF}?SB4dYRDb`@9@Up@Ti6nj`Vi^lHz*JIb6yq!^+n>E{M{RxC`W* zI*KLY2#|h$bTT84vA)S<4Y6|`{<{iNUi!ec1h854Up$o32FUOqBee%|gc<1sq-74M z{~>=U8rP}&(^sq$4*Jx_vtg_g?Bt12YweK3XA!c#Ylk%TZ2KZ((U9i-tkt9_HK$Gl zGRscynyGO(ij>^6>H>W0d86RNB7Sda)(yLKIiM~Cp0_?7izMhk*csbm!(5;OtN#vd z)(g6NCVn0a6>hU7*51#$vCDG@ZL)2J#nbb%qvWgb9Ty+(TM3Yx_b^^nIgY?!MOw~S zLSmH=1}QTyJkg3OIgkx`W*zuTO4jAJa)g2oxaN}bcxqJ8F=`p}?|tF}aneO%oH9*V z)hN3m^sNWc7D7&a_so8OCcP|70<5ip4ww)mbB0rN+HBZZFG=Swt11Wa!;ki40`@bt zx`!gV<#pHzTuY7lkI%o`b4*XQ-$Z?QsaTGSzRLyC+niy&^^eKc@}lN4G&)0yuhLp{ zKaR5-ns_~dEJV)z6XYw zS*u$&vj@BGzL86#M*p4Lx*@dmmR=AGgSvO@(3NIiR$M_MRyWJx)n|rkOVo1q-ff-P z3j>S*q0}j@lcD793jQXa<@W9lX+RjzdS#fe0nqhHrq_Zq?`eiotFP-Tb(=nOHBR>a z3vF9BVW0E~-Vtk@?S6ZUn^mEHQYp(X0sKUr@LKsD^I`kwh4il|P6Ilx48b91+m|@z zDG7&%%8maW^!umt0cU$8r#cFezY1vvIER6(0Y5^G7(2TIa8@XNLlJ~Rb2Esy+b z%crcEa8W5<-obvII|GUKBtiB2KZSV-OQRLS6x6}ZqA)*um=|_%!7|N)FA-6O=4swu zIv~$R7OPbW;Uk|hb7xQi@#NQAT9CEAbr=!lI$t(yfnWk-zj0fu%kqQ1iHXu9_|=ap z6TN%58;(UgudRpg;%uXp2ZiQy@N-zQAvaX#La?fw4coIH6UPNKQZfJz>PL+_G1YCU zz{TOWz^H?SjGKYP!Zh|!nyYx`S2HdKA_CO`D;@M#cQhcCUq@&GxOW28TLvY=kzzUG%H)E%i% z1FjDgQ^xW)ZO%#jUY2I|8aR@r6Is!afheT!Z4Ep|Les* ztnOu?PWQ_@^jw$_HN##zC`KfLsUE=L7I&Rx+`j6R`esMLDt+CU9C>Kg;P9XGvm9zf zAl!5sUWKz@B-!-zvmuxwy&J$32`0D9%uJvJHLL`(&4Pl0@NgU`G1fsEk#kgngO%xs zYev>dM9SNteHR~@47EhOcOwsCgfB*z3tuZAu_J|0*HU=t#D)$WxISP}v1a1nxM1XJ zLi|`^!QO%iXrA6^F}|WI3}gBiE1wfmw~D$!_Y7EiOIWIjiz^^JulfUIqxK&=&30!C zFK9n<FEsvy5n^3 z&%-o+z~ShWS{r-^dG>IYYG;4xtg-P=wElS_UN-v~eF=-TZkl)^eGYJnMA%H0V0V_( zeaIDC&K}Z*a^y5FiB<*Dy0frd_|D8%Pk7{@<_+SE{e+SNO{1p#d~CV{pY){buKn4r z#MCBfxVcdj@ro@CDTJ8;?FLqt0B$+I1dHGD$$&ZL#Gak01#3#>KKVxpnv9_Y3B=NZ zBlodI=>R@WI|%BlZ`4Yp7G(q+1Z#DbP!}%mXHQ2rLd4763U!K)IY{ zY~aF~ow0Q9&Q7biWL~vt6}Q5x@b&Og%S)3P!WA4SkWsYuy_n7 z{q)>=bCV^d75}HceQf8=(tGQmkJbu* zt8PjjfIy-*`io&DSfw>J1p>Mr5Mqv>rI`|e+LZ=3bhAETNpK+-)#o`q@*qigt{p3C zzI>E$k1K)+8KF>iLj&Dlrd4731FA-5<&(fMTRRKHKaHO2xAq?b3DG|y6w8FyAMJ)so1Py6FHtNo`?(Igzil%Q>2ZTGtNy#ahPc&FS-l`R z1hi7@H9}8o^m*yx?@ewfXWiU5of(?n^2`@8cmc8BuYp<1w;_qF$jyX$D7BcDrdgQG z75na9J{qrW=_oK*kVgOYA4!tml@MF;^4F5>av%0*CTSpRxK0T z{nORXvo#e!V>A0D876c5)i98y;cj#&(&$-4n|tMx^KUH|-vBygU}?NRbND%lmgd4} z`n?nb3Ewwtp0(By+FJv@D+Kr|n0WygC#Sdfd`N!u1DPwsWal;Se)XFN+Ly^4CmL%4 zNRzoQ&f8?3C4y>{ci0Aqldy=K4GS0-+F!MU`j4euniWclf3H*JyY>`*ui=;z68uaA zD^44*vD2R2RhxQ@?qvx6y|u(Nmqd11Aa}+-ypM?|gsu6Xwa@F@pS5l2_A!%00SxQ+ zbisA0r+IJ9j0|Njj$=3T^)9p49rAZ>^z1b+M!7o@5j6C#ZQ9Ioz%a8;L4a>ufp(d4 zbb1*s%MvViQdL~3lN<51pDL*H_!3Y;S(?W$z&qXH z!)MeeZ+{hi!MkATEMYAP8aPW(kwJy6?oXDUS-LZ-ee4#zZ`eYjKk)@1j!I+5J7^o3 zz&i|uwT=d_SN)nyNw2%W-<@eRhm~VZ19J!VNR)~n?B}nu#)tcf0)ef?k zKsvlFcW%4Zkk7i{jxbW7C4huECoe3A#Zyh*XW;j5(}rJ6@hUeJ9kQ~K=BbXXEhkZ{ zGWeVqxOuWzDHLF$P(XM}Gcr&TKU2}w1g{opHBm_4j-agU5dV$ISyooI8JyYCk$1x{ z?;DV79@KDvYK)|$LftHhpN_G2%AsS-)MYHk{hb zWG<;DL>F&Qn5$Da>1bjj+p*6wAs0Y&mA~q@w0i=mtuM}cJd|okCPqe3n$+WNf6C$x zYOc6tv^B~g^O7W4_uiiye60H>Vw(hj{}r4(|JW~abayIR!Kc??Qqt0(ENuRi36zE0 zxN&hywYik~-qpM95$VD9MBWOWq479VUi=kuzJaXFelbK5!y^6(3KOO}ggXVN_)iLt~i&?M`W(j5xW)%`l>*?5%#G|$2hg>N-Zvp{e49ZI=J zMaR;A5on4R&Vrf_3|aL{8p7M$uIFcm)HI_$Q}rV=aPJ3Nh!pZ};yK0jSc%c+Mxb`R z-c~6gflgK>1x8CRDsxLVIq8EM8hXzX6RwmlSPU?(uP+)G{W99Iu4#K==DZ|X8P#Fr zKFk3pb(GI;{ReST3#o#E4N>x8;c6q!0+LQLEI<>$|KG&~d}Se5TY zVpZFu!hI~Z%Zw~*#zord~tl|Gyp2O^~vrr1y67OLIqE=xPwU_%X5j;Hb>*l zQrJJid1)SICh5?pwRy*H%2>!LHaOs5)&gp#2io|E(Xc~T@!(0W-U-#+{f+3T>o<~^ zbyTyonn{osL}G<|u=w|c3Td-3tdl`Fd4Bryf(o&IOT&hz)b zwW2Woqiv=QNw(Hk3NMZk>l9>y7W};VBH&sB1nA4Z?C;(f{0CsvAxSa_E(;s@KKV6I z{ElWu;aj)t^7AXoEhw{b7DDXcfeaVg=>DBvi1L+hX8Hd_%~f9?O|Xy=rVuwi$+ zu#HJ)D+_i=0;S@%#B0$+SsMdzYL|k6;roDGQ+Y&n*(;y&9zn8kuMVzKkUX+Vc?XA* zD%g*8f{;K_3af!xi~*N{kx}eHVs85y(RuiU$5*%rGH9X>^@f7DGHMruiq!COI8eHs z6zQi6tO1Ba_PerF+zb<1WbBb0tcQf~8o%wgj z6ywA=`F8fc7D1b{%5y4F1vLaj${)?YA;h_Sr7R3CjERi|ji4Ge0A+C4Au)A)IC{C`{T=YL4ahtp@T^7R3OehVlA2W6-d=>)5# zy>}Q=N^eoG{lW|~-qe>+M3Kt`YZy#F-p86Sjb;A^!9_?RI1#%is>NDUBb9AWHEu~|xMxwxLtqAs&b;nVXraw-TN@4VFs?!XOxdBy2xYPY25)onioqXG+xPj4BsR!>jH+XX-xPWun zmRNd{osX6DvkPqe4!R9B_xgQSV!ftj3PHpnsn}&6rgwn0LxV%SbxhfWr}zQ15%r1W z_ABbgq?DIy1k-9?XjJH5P8NqgWqi ztewX`yaPXARBiU_=TO$-0_H1S&>2{ro0Mpe5ht!f0-a&WKuU#iIc^Ja~N1;AG7 z-^BaUl|F!8zV;!ShyF}0K{ejxP-0}>w0lvYnQ;)a26~3b{YNQ*XHU^$Pqf@}7ydQ~ zTk!G2sMhmkKQ+O*B74X}fnx?Pe@jjRoo{(^!n_(c0at7&jku0u_F@$7{`)(u(k~XL z-`{%1!TA>MNN24ndUMYf&{~~i+-C|P^$~|R{_#9D>Qe+t7cV0>O6W3sb%9FIL4J)K z>Nldr-9y6x7lD&%j611&GpFDp3#aao8{y@>;*DS74(Gjj)pzb_ji0G{I8l0=-3c`) zV|m+eQuWbb@pfs_Xg)L{f~R--^3y$*HD{t)U4v#-l@x>li&~UwnKyF|ayQgkae3rK z|DV{Mnw$jir~+7J?cFTo_gT-r^U`f)KT?UNdX}yx|JZW9)d9`%t8c!^C2tyDzym+>#u! zg`M+@ac&GqP~Z+H`;J*WROoydlMidJYjzuJvN6bbe9yimPEZssc9v{U_}M++_JI3a zxOdz^U=C@5h#JLH{GMJFx`(PXTs56i3Qr!b3DD!(f%*yzaP(a2iRq$*UR--S7>LIA@gVlKZg)2{YbsSGoUR_MOzv;hK(N8a*J3G&cu zX%7p&C)(I7ImN8u8-U6G`}FKxvqnk1%*IY4xfmB;RGaaT<}CQ#*Bu)k4d+WSDQzE! zux-K_?r9kdly!?Q_sdnX zLeag<$4s&z(F@7Fcjr8g3okMp#xs#En*ssJ`{VGPyUQNykv=B1hL!#O80k^1l3#jI zRxP#HUJCeY5V8_Xbfx zwDOV}U!%DE@Qi{D`G(!3#s(eS4;9H*!PAleJAsgnj_xCG79;sehjmL{+Cth<^f7$A zXV?9y|2=(PstxfUHb1e&=)byf9Gle03@bJ;8{RQ~i7<$fOiM6m=ApvHDnfqf=Zfc6 z{1xW(M2n|Hu=j@Cz)B??U7Zy5-iT;Db9SZuoBJ-21?u=&poew)yyuJi*@t;wne5@! z897O-J>GJ&@<*pJ+$=Z+iOKF{0oVqcC;)wpr4s&2==;qnc*CUvEL)7<(Nxq?4w@>h zb6=N@qOoK1TsB*cX_gO_+II42Vy!+o{}gxQZ%I(T{&#qOG#)FKK1P=!Ah`Sq{m#tj zG}v*~LL>}%!v2qvDSW}r#>)%#2rG`NJAG1ml(fVgD^32+4Bn>`WGqw@W{=S|!DUhlo9y0>)LA0er@T$zBNIOjBw4gI#=YFJ~Av4wsb^lM{gpe2+`a6Py49b3QjhVFwY8TxiwLMr^SD zX|Pv%@l2sw01jg(%zFnzelP63%2#-P6N6%~YnqX1=TnAg^JPi@dHhK@9iCllz{9vf z{m9EB#C*O4MpY)Jg8yIDm+0My509&%R_vnq9wxP;_B#dG2!X)%M8r>HwzL(C5JH0e z2(tFKSh{FVuDG(Wy0kVf&lM^C`xYp!{bR9A1=wd1H7?4*mG`T^N~bp0SP2R6o2hQG z>9(bOMmGKj2njvT-KJ8~X-jF3{O{|DfCoWmX7%2R7cXN~*z~E%PJS-p&z|30OI60* zCxy|mjdU90yH!sF&aN0W2scubY%qdiON$&3vCf&I(8^S3<>W$Q3oVwPet%rC%^4W z&M_G?@Zm3V%H>g0hyP?#NCpGDpvoLP0Lel_?4x;&RI8%nLgNY6tQd{5kfSb+Gx=SM_O_ctYme9) zyT3IWi1AQ?X8h3FEx+7dIqmN!Pw7*QJFhYi=Z4ufKJ+MSH5Ss9AohA`&!S&4!udOC zdfInue!h5~-2Qb^#zH8gb)7)A0syN1a~xHEpX^&^Z)WNIdZ8f=1S~5aZ*;g`XRLzg z)%nUo%*dE_gIVhc0a<2@h@I(=S%1v@#;VG;dsfftpP)J!rbgdk8+XPKu3 z8Cv9agTimj$d-Ad_U57;L<@vv&v>PVeY{P7&iW_z!S=8aUPmCp6G)-}WG4Pcn?BoD z(cZDpV`e+-w((R}dB8*YUSB1)aUxb?B1G`Kwbd4nh&B28yM?&vfYc>-g7c$im(NiO z9olE>g20|N;I35x>XaYri~#aAecRjsW-sNszsA<=2JRKH!Fo}K@pUKx}O zur02wtu}9u_sd1fcKNubFlyJjToOI$E%|^`;5zG_&=87YGvJZEI$W%d2UtZ&DHeD zk|`JEXLv$sSun6oaIAa_eQ{WI{lYN1ZP8w|zhj?**gQB>s~WLF4QyDi54mv_J)XWO zl^3Lhz6&Fx)`#vVD1SIAq#n!PX+@(1DIowSCLmhCX1V^J{e#Dn2Qq*YR%)&Uer3s0 z``wg_g6a9%jA)BcExOQET?3D$R;C)p57UQI6Z(mqR8VRC_BH3>N{2xjzT;sNErhXh zem4a*tEYX%AMZ!KMI{pufkR3yu#%z$u|p%=Sd;VGip_|`*cEy9Z0~`?8G*ttO8CQS z1izq;_(|gf7Uh2Q@{D6TO#aLx-H3;#*__qb*SPWI`PeYMVXE@Wux%?Iga)3ac8U2~ zE7I2&(a^Rkg(u4H%|kV%0shx5kFU9CLF;M+lcti;dB-OXwtBgD*llPC2{|bomuMlm z6-dUGWG|u9#qJ8vnnwgB+X`%nH1NVoB^S+EWd?3IrnkeZJFRp99>l+DXmbp35(0FX0b1%UvvU2KS#;khjGO$T~I$oLWS+oOBr(Xg)fAi6ghzfz*w@d>MpVinECsw5}+Z3l@%&ztX49tKk;$X}!z^}S+QLp99 z|GOSJp+M6C?Fm)|4jdQDFnU<{?N59L1rr%u89`idHEsoL8flsTA&>v*^-H~|=F=y1 z)fD)lkMG`H>Yb+`wsA8GR3R~ovZpq_m=+oZv}GV8D?7+Tf1H+{Nq_a{KJbgfzqI441dvGxCXiWK0?-*d18>JKfu@vTfZlU1%4)? z_O4l($1y)z@?U|}qgmK-nU;gnH7aTn zW;fh!_e6*w|B``LkH|!~z(7XRzka{BwzevbYC&2LB(!U1?T;jRS)y8Z;wK#sC0hI> z?($d@ib7d!UWj+^vpaoJa;9d--PlAqtxo8is7Hk=S=qy{75=pPIdggUZm|m;c}zRoi}<#*00>!O4f9%^ho-1T{ra&}QY6ei_Mx{fqs?-qnhSFo(kEUzXL; zpew?Ct7>dG!JwBmqeJkyQFF}de{UNE_|=vqI~;bNQlLp9Xx*z%k$I4AIG&K8uj3K& zg$6e!L=+FQ1rjyS_R;po<#5e_Xxi->8r7!Z ze==i}PWp;;xJLt^(iRGjM}F7MralhTRkU6jD=K_Pz)BW(ix{)QF*5A-<@%(Dg_Vhg z>{HH~_M6C|FiawGDmG6dH7p|d>RBoSWn8p5>wo}IM~JYZN4oK7;=T)#6w465p?Mu2e|2|h+Ru$)b;gbvCOTC{ zL`z(F+J3>m5CDs4pDZ8eD7l%EEi@HW=RH@P#h2tiS0GTfNbuc{co0SH9xC0(TJC=| zBGU`>dAl=lK`+7LK!5aW>P%Ds%QNh+-p*9)qzOx)yJfLwN0WG7-ff)bLW8SUk*fFZ zS!P8h6M*Fcna6z9v#-+o`_5Jvl)}e`Jm88+fgD^NrP=xwiN8%x!QEes z-6&);?J;U*IqBbE^B3CQl~+}%R>9Rr|NiOlKF$U5H6N7?^OmdU#VK7p zd9wYtEN+u#7=PW$-GUmo_oZ}YN<2)~!|Wf7=X_eHPVZ2{S)`O(sH)~jU=|R~d_NZ< ztb<2n(H!zVXDfkqEl2S5MecX|-xuxpukovRlfbC`@1MF7R)}`A8z=KY%p%`=*fsa+ z(Bp#Th&(^F_F@8Q%?LN~%q&Tv7O%T6J5GO0F@2iZ!_SZ~&b^%*e9w*dGk0Vji?-S z0n3K3k#PhgAv%D^KExmCZ__z75&@#jiOe}snvwE&gXdSRcV9)2%iOAWycJE3Ly6!P zrz3f45!8xIr$@0%N$;< zh&aU}vM?3Q&`3Qi{3%8(9)~}Sor!Fl1w%GhzRmWCU@#dQed~5a5B=ckJ~`*x+(|*2 zSW=3Q-~8O7iO3MjAvUaFBIVSi2-9KJ!?xO;Sorz8Gap+Aum>;5yK>P1f9{f|`*_Ls z-X;&Q%0mgt=y6CfEoX)HIebK{VDngQ;hbJDE z^KJ66QfbJwW!QKwqA095`|N9;ShRp5Vd}#>G>jV>9g$cWrs1h?6sZdHO}9N8%8$^3 zx3GyUj(k@#v_?72?(#7(=Ys}aufb&Zx{ECi$SsptY4nr_k9U;BoU2CU*L-N ztYQw|EQm$-K!0MMS34))UqAIbpO|Vs%H2~?TQTC{)>ik~E)S?*sy}HJ&TwOh+M5S5 zPhO+d#aHqy!754kl7^VuT*K6|2(0GccRcr)%&HNCU*s!C?wh(ejNQ&nd?@RNna zP0G@afA~!XZPH9iY0``!DijH*K|Q^OEX`jYkN@Y(CrM0D4bZ!weN3pcO9TH-f3WIF zsC@sv{{1}$63{0IC`4GqFqeC;yj@Bo@OvMr-fpEGEeB1Z+$V-{-{roNSB&P9d|n7O zRs4)HZ^gGYOr^`!#a{4Vn2L|Tx@wlAL=k?XMh387R!KAtyd+*IBVImn0mU(SOOlzH zMNgjgrNQdlHMQjRam?@RMBg+J-ULmQi1Bd-Nbq8o3rAYRg?}WOy>RxwcznXZJNElZ zld3(g4Vf;~d^Q=ZH`L3r!`%Qnhy?~-PL%2b%o+T|t8}=(b*c6L_v15Y`9uRhyOdRF z`vkWUbo!MO5K6!QEjV8a5u{z9y_ZE)4KMk_0SThKqB|SIZlX3}dStyj5DLrNeo9W> z>tU%Tz(uc*e^Q;}<@uIoh!twb%%)_H(^6v0KW;`49=db_T}aUi(xCP2+lbJjH8wQ` zK?J~(0m&oqO$uj#^(LUm0`_*Sg~=k{5B{x*7r-M)eurest%84ulygK)wk));WvQW6=s~xnD zq>+>m4+U(c4pI@45rOih{wh}yLWuij?x98SKm3tZnhr9qkvz!HD}j9nqQKK{$Fl>X zW3?kuuw;Mn2|YW%g#|}^Y4Kb=9@K}Lv8}`Ja5T*qvQ}vsUL1X2un;k=0`#?Rv8EUu z@s!v7VF1H_oPqBn<0zNoP{+#k-lexkG?JL7yd0|Y8~M_c@90B6cIs*c8q?k*%DUDm z#YKLttE+2jisyj>;t{}0Yq-w5;xU`Wfx-h(^9t`koi5Otw|Ug@N;ZG~oSnzVp*NY@ zhJ`IdCytr7K_;S3U>(W^d+*S9@;IRXN`NSZm+I~-*rV_rj=}QwBq}Q+gCJ^IC#vjP zcon=qJcBCp6+1d^p>G&`%gDy%^x+VJfQ5pUWO83xS^HXJ{wc@L;0K(~ufXG9c0+If zgPNa7X8{bK=F|5{<@M9GW+CJ1XnB#)bVwzR>=&Inq0B5{@^&?n#!Zvgi0pueuRsMC<))@4)<*EqHix83aft}?P=7RbNRvGybWMepLh!ZSk z!H(+qykHa>qkYg<|GL}Ns{5q8A}pn^@R!TI1h8)bUaYgTv#~K9kT>CJs>hQ0qsJAi zm&)K2c{xuY2ec3#$x>X%)J9y1D5sDOpi$%HYHC-p^)a~ce?s2!V$@p%>-D#mVjnTlx}jg3fV(G4so=1x+$*Yp4EsM|H4PAogh-S;U?6^ZSGzots-Yxwz)rf*Q$$xlw@*Akw z;6yuehIbUxs4{0Dt$)V(j+eEff78Ef>0gLVVz|4xfD!?`Cfgo;R#p`$K_!; z$K)S)N_(032-5uB+CuhO3(}bPbyn2$FDbmpp9^EPs-30e2ioY$s;Ulpq6lPNMQ&I! zHW)Ur#MGWML~)mxC`feeH$ExH^LnLTguOTJ_}Lx@-%tQeq}ZER5v*<(#RJX!!G&cb z{iCOBvQtA%^09iv(D{-vyoP$~x#CZ5g{I6JCHQ9nT2Lq@d^%4{As@kTMU=yf%1e=N zq&ihZvMasPuM_uly7_t*OGjlVBWBG0fB9KilH@|WV^6#gyr53VyTOE)DyqW*=-h51 z4QY`tY(3hGLiT>-`b@R{OnMmu26eTy1x%W=kFj|tAyvDR{9q&#^$Jtzw7j$!1Bp>3 z)n7*N-dJeSI$=f@6HjGv6=MnlV*jqpcXltiS51i+bN_5tCXlwjb8tF5cQ;WED!29t zA=l}a(TsY2Um*!DfS3-s#%81pZ=3HxHv)>Yqb2`X0+r|VrrT)mFoIt!H8wvI3Od1p z-l{;3H#w^QM=>L*;_=?>2WxB|>~$6fhIo|`c1*@&F3pj#l5MfbuO>=YDb?a|+p%>| z^L((!tU=gXdp+C$kDFOc4RnRRB^;vzrSrHXR?gi0WF;#Zga zFoIcY2l{)BhH!Oo$(iJW8ufXBcu{(t@vf@k9}*#S?}7{N8dZ2a=qevgmuExLGw9YQhb4i;m@Z%Y@ z;wm0~wx-|jPMS-CXv+h=R=eY&*|@v!%M+xKezk`Dj5zCqqT`yO1Vea(sxJ%xuV39K|Fg0G@%!DF=i#%68hs!HA7Nua z8%$t-cikSe>XCgP8*i<-rm#jf_UlP$Jk*Y!h;T*7uwH!Nmjagfp|#2_b5;%d#QWZ9 z{K!-j*1&$Qz?zp9bHq~f@h?fn7F>VOVcuIuf7|wyo}4|+^ z1^p6%4-J7H*W4fSQh7XK9lErKHh_w6}-hzsV#{X6X3syLLP9+(KIU(}RTYqid%~)`(^n zKAgyJ4)Z3Yvc9)UlaBGkMA$F-_JU;?oW>N+I{(Up%LLv-2_d%72tnso-^`tKC@kFX z8~-qGQ1j~w4Q3lH&Xdbr8+oj1Da|_G{>Jw-_8DhNeb9d?OTIHe3|~A|?s=)u6S2q_ z^CrcrP6e5(=fi1X6J z30}z&sp19~f7I$wQ2gBU_b)Q-xwZUQb&X{{GX1YwKL1AMF|@^!h-wCELZJ+LiPB44 z?M&!uW#~n?O4}paa|iU_(^~k+YajxhTUR%;-#b-PC|fa-n2BgJ9q{GgzNvWk$djra4_hvh8wXcRyNzr*W<&!UC7xJnkj<#~EU#AKw zMEg6Wo_sS4Dh-%G=XMSWvXotr9{%ZEQC$8^mPM@cW)^`td&f1)ZUo*E4N=_Cc9xPerRLaD=YcL2^f# zO{wTY6tx%-+_WcM$`?%7hC}_u1Fk8!^y9i5c?m<0u;grf7QmY<9`^hiVOTOiG&qxJ zzKq0xHpz+_q33(%J6D8+7SXmek8nq~d;Y)P&io&${g30;F=p(HCB$%(hBW97BAT&8 zxf*Me&{)H@6bjkKm>GMGrJ@v*Ew{3jLXxqQWkgx8CC1(*m15BM<9;9Cf8l$6J)iSF z=e*B3pU?Tc-_Q5!Grl)qEAC-60%y46TB{wn0$M*{N`~P{Py8ikLW6M*6cocy&+}zFsOrRDMn6X z{i#<^L9kh#hmf`u`oUL69;tsecas za8D%}53l`h%UzWs{%nl3tjEXs>1(>q$;G=Lqagok^+9BZ;|ssU)}9U|;A|3baQ7r~ zd|89Kmgw7wNvZfM|#8HlQ11l+O0Y_~BUrYL%~ zYUVz?TT*N{)?^^!*Gyvm>*&ac{*&g>bJdyjq+T>fPVVn9z}^k5C5U~pzs@i536(GF zlq8JI8lP7564`$qG_(kD>MNRX4XRg~3YK0z8+gl%?M2BHNZ1>d^w3pSpQ-YcUkZQu>T-_4eZvx3 zjrf>XbPJDHg5x@RzxO4s9=ji&O*ipaJ4`)LAQXMPFgP~PclLBC+0W^X7YgS9Z)SJU zl1H;0#kg7?pQ3s*^amb2eo9WBbZYJ7)1>&#Zm?%u!yTy!jFYZOuM5B__dep!m!|>6 z{sbBxiur^}@hK-OQ*gmO=z|j4CLaYEAuj4Qs{+AD0aSK{6@z#x4sX+=c0)BC)b;!h zX8c^8P+>njv;{N7#or=*WA8$lvYmUZPL!{n%=W`dK)AS0eqRB4#JcRP(ZX}KTYbH# z7V=Yn5=%{Uf|eHx~}6&k*C3b!KZkO7a;z85!b?x=ndOnEq`-*-<%4+#;#& zSVR(tvv8NYJqQZEyGW}2V z%6s0)8~JudcMT3B-8?c!#W`fJGso;%!OPa5L_?bnZ z+WDm?SFV+>UfVh9++_ph!iFfFUOC%CfMVW+vWr-aaRH%GB!&as%11NeSC<#roM)@; zj&0!|dVe>nbk|MKK){r!Ddxb@H*bqqUgZlceZP^rdQ)AX;l*K!K;TZ}A*2KRHe$e9 z&Bq%x_8Bp(c>ByD*HNP|!t}Vh`P=+H*RPHG`h>{|1pqFqBU(prn>8}*2NKc4I}8v* z$JAaejM$iSSlH#IzKW;4{Zhw`kLl)ZpRHP{r@rfLbLWcLx%=L;DC1s+ za$|Io1-(u&WMeT?F2VgYVInGmMb^+Ayor$3iQs*ql| z=6sxt`L!PqR;1WE2NZ?rhZFgc-K0AKbJuqmgG*1#%ex;mC&gYmZ8;wxn-X6*@Yt@5RfMlo z%Ibwx=}AA9^pZFh;(FW^yz+uyg{jq4&duayj6hfP4s*D#WAnfhd%ECyBL4wMuCw);uYin%P4oT95w9*~>-3(#@I! zK@~$QiY=XK>0-+h3P(4*V((Lq83o5gZZ)BeQDPp0g7(!Ji?iPXrsaQ%LhgT9ei#xx zWUS~g-x2v|!j>KPEnW@jRLl>ldxBMIg4JUl$%D**{Sc$eFworXK7ze8Tp>>_oe8wL zPN}Z?I&)>QUh4x+{@mp08n4L^ix= zGxpNL{D%ETwb0JO*TLB@oG=H^s%KZBO7niBn6#M1$dqFe*889 zy5Mcyloh#E7c}?^c)c_0N!ME9!5bepZVxVXZSByaHK@!%ISZ8~#ZO!AEfW7iM2}&x z&)S^IQ|p{sjLxy!yA`f}Y;3)kQ)|4=Pk*lXa%vTxZUlWDr>bV^nFKJ52*1)V*y$B0``%BBF zcX7KUM3PC=jI`vF+fN>7p%o5>=B+ei{U=Y1OE-^a>ou=ay=}9budT_Z?+H3$4J516 z1aE2gj1<4Xc@^L zzf;ZhQBF?({8=*zVq*H%8dC%h%bV0pD;u)86LSaHJ*|HGWn#;_Z%OH;?=CJUBzY{H zJsTeW`Yy$Xkt>|XXW$h@26&Y7Gm9FQCIy!PBnquJ>Gmq!nIjVoap6CNr?DfE9eS2H z%!WPO8_|ORa1GV}yHb?_M3mKru)~|d5_=G@cSL>9@>RNoIfhc=0W`V%*v-iJWtKiI(IPy{R38AVN&{H*6cAVJ?NO z@zCXC61PjN6_2_(dB4P&`bL z>qu~%W#{dh(p+eFCjue2Z8*=(bU@=0s8^WutRb}MJGH|%Z|wt9Nk({PB>_JE4*(I ztxka6k_Pvn7-t-PPX@XO8|4F>m1BphO`9z*9JwF4ym>rDy22d|N{41yWGa1Mw&wH! zO^Ohxh|+&gM1pXgPWRXgr@7el(ffL*kzHcndEf!#wkBZ z!-#|YtsHwbMRy=+gT9@$X+rA?2On^0dJEIOE?@RM+g-XlkX*TMk)-#UNR`5gfAM_I zD*lB_J}tvJUGj&jKDN{kRh>0>Aoj>47t=$i+ z`~PU^bI)0Ovns4w;nqE8OaLb8I4Set*t|8pv&QvqgT2`Xb{lVc71`;-8}fna<|@-> zWcu5~R_1N|e>3khuhG8dE&B>t?+5Mgc^~#3@9QHPK73(+J!{??()YBvd2^|JkAc9` zoP-2`p#>xdjPkCD!vHWCght-?GFqfYDETg#Kg~kZD7Ofnxxt>q;_+XI4W=5Bqi@j?}#K z2Uj~xo`>SZzcv{!8M|}c0J7b8T;zoUu*4hNrurSC1DfwY zy7GCNQF7+YH&v({Ekc2qemc~l{49zxm@vzKdiN7E#0O?3NblQf>7&hZpWi<1Ujx zvV2c33XuiZPeMsB$-QV0kH;+r8xy82U;WR{zUfHq;lP#XPj5#3(#c%r&B5J;YopC< zX@D>i>c)%<%oiS4fyQYBQd4g9X63s$o@`HDwCtU=o=V^S=@hNodT)Opn(4kcV|U#QMk7LC(E-lCmS&9N&CjT<%@$157I@_xmO+15d(K1U?LkU zaF;3;6oN^A=ts>nJNLKJuH~-4ROF|nXNJp-lF#M-tLS6Zxe9snaWX7f%Yao}bt0O` z$PRCq$3ECT27+f$A=v1?vB7P6mv8zYjO!aQGG=mfPmE6Y`PPVi`Bcjs{xp8W|ICq@ zo3lH*og!-n8_xg|KBU;_efoFd(@i5g#8mV-#@a<*^HI7h7cd~=y%C`MSEg*Gn?63r zpa=w8lANOgL(7kxsP!oShIkc_*|>Dx;(4CoO?u55s${0hE!Bf~dCB;~ehSfm0tSd< zlA?eRaxj3B9Kwd>V)g?M$U(#w|h*S=?TtsXH-9$Jl8-b`tk?!k@jVK}N>^hPAgXg8$J50)tk zlBs|&4qOq5^B-?o9-<$*rNw{#N!ur#10q)}&l6pj8g@O*iN7sGC)Ll-vr6Wi>tGAU zwRV4HQbnjsCpswCxpTIy88h9t?fhoKsAu^M41gfbyOp|Xwv(iazP9aJTlCUk5@?cR zL=ljs3D=d0U6qbJ^vNW`BH$8@KJd5JJJ$`U^_}vt}bnPFVCVj@@>bdO+&V=w)tbu_D(4r}; zexp3z%l~dB@em;L9 zP}ua^@^s?mzMTxMcO%3hq~7ODcl8fz#1Azq;(?!n)|Hd_`Z{7-rZZ+ku%2L_lzdZC zEHtC${9+Xnq1bCtUHkcV9`|7*n)q;=yYZ$#>aG{-;^xZzh}-I|zdAq@2e>D8b??Qu zxcHK%7j7V{rC^EmJ%8>zw)o}p!-LO371N1TQtzV|Tdojp`Gb4ig6m?At!nrV+keU; z>0^l;sVeISzo2g4o3`x4aq4I1_pMjMn-T{kjsKd_%i?D&zgYd*!3e1F5ec8BEC*;U z=u4oeEUmB6g}h=H5*J27;O|dOI6JpLE3|S~-6{g1LNuOXF-bj~=8g`;qHd+3?KWT7t-}Nd+FL6?ea^ z(cW?kA%P+<^5LjuXp$*3oqrcO*t_{u8yL1>aoI z{xDP1S7YMW?DT{Ii^sGtF9`3uf7_Pw-Hp%6iNXc(>IdLCfba{ip~xADo35RK4Sy@) z<~1Ud4CWoYWN@Kkdm(VQ)M=Hv-Ta^FPD-3yA~;~mH=jzi9L5K#-itDNsCu*Fa`9)S zsmZ*(S^C1U8QOXQ|CLW-qY3Ipgn%)3{DA*JQwyp8sH@(~I!xRlQz~PG(F9@b23kn3$c32L>w@hk8%QM?T1( zD_oXSn)P#YIPvp))*J2{yY4aAFy0<)x^!Fd_OL;`R2I_h8x&^WzkjzxSl1FyH59YhbR0!XW;x4=hzsta|ks;i*2uVn~ zA+6E2@?(AXBwf(2^BSebZpCDdFV}HlGYC7DHb9pWH#=soQE()q<&PxV^R(EsVWZ6L-_602^IB;k-Q3? zoeQ7PHyRzFLL-t_EVtoPBE7zAE`~il_pg7fZvT?DwcFjE$L1v=Fm;(qQ40%_KD_rF zmb?O8BLh^9x%7Vc%R5Bg=419(26AOeDgUxqyYwfo({;>AFy{QyYG~p*P-?^2kf85& z6C(BH{0KLHfq4p`1!9?4cUo0pEjxQby&0f_715?ub{cf9nQNA~Iv>91G zKe&)OuT@KtY`$tnr%K->oDytEy$+$g6ov#~i8@K=9>3SRQ|Ff@q28c2yX(>?po_O% zUlbgXxQUAPy?x_*m6S9}5pPWTNV`~V9(m(OZz=*r?!2It|5>fxVhWlmxL$>wt1Cl5 z`1!3^MMV2%a|1K~s9Yi$ulVP`JB~?R6t0Um87D6#!+gFzYs(R1h)~C5|RI06qEl6LkRlk&?*BT`YAkFG^7Qp|j zoCVJ*{ke)FO4f*`7nrJ)S?lD&r29P0JM%Ql5IrcWEM0J>DJuhfx$Oyu4vg6M<|Nciuf+V!D~FZ@uh( z+`aGV*B3IEan;2y8E2Zz82z=t3Enf_i&U7n4nNDB^Q8sM)T!1&=Z+IpoA-I~C|j;V zq`j^yL$IjS(*yL&J~BhyUkm71RZSBS!^i^GuR7msj!>u*Wi&C;`=KiKuJ`O4|ILM% zeE70m7VUjINJiYpm1Q;xAb9I086srH>pV6ZLz{@9WB8y3hr5qbb4D6H3y zd3xGk^%6@S>iM3*j6d()Nb^bG)o|q)LcVR`Sm7IWsciPWBq1n5wvqVPfGE^>e*TE% zEbsSX)G3gUl|>16-3ZzYr>7qW@$x@@*8I1wO*?<9#Bj92;9Z(=GzJk*^DeAZMZj)9 zet@aV_UxWhtG^yxj4@L8m63nfIaAlYe>RLBhuuFds?_Yrz%9uADB%_O zzLSgLH%du4;7knM_&ATsF0n;<~JtG*V@>!un z$4sTol6=WWMNNH-fXjV77LB7=z&+&!xZX%)pgFfF$SwF!yzK2ScBq!$zy$Y_w#Hl& zG{LG*^+YTqw+p;J-U7C5_ zSHN^t#`KAYl(gr_LgmQBc@hO&TOZvEh$;LjQh1s4b|b;IyoywaQrCorufsnMETut0 zf?hnUZ#|epOC5F?@z1dei|q^Z8B{R24e;zcyJ|8HUQsjAe0y3G@I(i$`Nsri*-K4p z_<2aLulqQk*OuA-m7o=Txv{MA%2`;Fm%Xt0?}6~KE%97XH__W?y(W$JgxE8eCfA$f zf1;CoHmKkS@yFObJZBy-5I(bb>$eq$nSWH`+n+s$#8=j+#AFjDmPr(>%YXdoL)US9 zn4LIo&6m$zZ+wjueNhwE$3L}6FnApfCJ#=&bTgnmFV+VISH&^y`GRgK zsEpKt+gE$ODZdUk_3QqFRZ-k=8MkaaTag&C_c7gX&h%n_Cd2*oXlpBs*vA1qSJ1|z zdA2sml62NckMp(u%bZ#wZl}A}Z&d@9w((Y0V)}|UXN(HD_AsFxQOc1BnP4OIC(o@$ zrkm@Ng%kIYLEXlJ?$T!xIqS4V<^DpTN#nm?38o)%QnxYkYKM850+Luc=v15CNW zK`-<5`3v0Fi6LfJ15_xyyvtuBfnycPjqyE+VIY*_K_Zja0NI7~jMbXw!?I0=+u?#w zZ4yrSRx+e01?zRqvF6#kzbMO1XstZ%CUj5TJu6&yWe+76<^cJrhDaQkYWSU@q<(nK zbbopE>ZL=yj0;F=OtwG5l^V=OUQ!jP#RbiA;Me^5R8_reHZCq8)EP+Mu_gm&Xjci9 zR&_5*6K!<8Zs#;`yL?Pa*A^J;f2DYH#l+SCB7?WPbA&7q?{aHjOgw+F@cf14Sz~Pv zE!j9r<*+I5?3XR<-U}npgEnJHQ@K|l zWiTsg4Y5zzf)t-faCqmlZ1Pqf%z?MA_kA`Q;Y@(G{SRlJHbO!uST|oo96_RR6~5sO zH%s3asgkE8G&(^t=S9m%i`PsRD?#}3Rj-04N)%Rm#L;4BZI1mh-s@Wr#kj3!r9PFo zE%HbC9N)qUru89ZV=KuJou-MOF%d#NJ$z&Obk6bg@WeG)fBQg988d1Oofhs)9%pqZ ztlWKI>8006>PYuv$d-Ea?J@t#>X*kaBvB*Afp0li6*e{HAk z(3LXdyPw-QBE@+}+MTVu8M)3v9n$8%n9`c)0m*Ortnj3oR7Cqh`?189(ZSExyUbPh z3rOiR5F&NkW-1-BW2Y3wGm;tWgKY?5R*;F2Ufg{%NYJC>{v!%cXEcVtXO^vy)#Z8W z(0tuTI=hcqL8!Ru(r&HD9o#d)^ON3Dy(8=~&-{ofDAC%mOEGRmJ-huqm}}V}MLms=!oh8=ITn*z`yjYdXu1orA?wwyv)B4TdCRUM-{0 zY|H@vpdPs?bD-(kN{fE-l~rgEjBx*Gv)<&PSC}^^INjqI&mldr+f=y-e#dvOZ1|)9 zbu5ey0RUT5np=~aEq$q1J~2K;>#pERD|1p^XZ0hI59d{dUL#sz5x|i^0vo~J6 z=0NXS_YH=iLo)y&HTfef#gGyR?I{5r$%AFgj64p+#b1TT0e;q(u^H9+g+>zQP$? zJS#)rl)3sz!U9ep03ab?5EIxNyI52(&|As%UCs~wGvR*hbBSL^lyUtxw9kFGX=@=j zTVu(iqwTB_Up}Q}LTC*KxxBS50NeD-FoET|=p1io*B5%8Pk;I_7{w&%u|GRz`8%p* zy@yW2#C7R4dlbXmT*{EO@Vq491bf<#s7L*Vey>xz8wIn0#KiS_*#gS*pcN2 zILOE_?WMSA@^(KUyo~ZA@f-IDnIlu7WP}EHvgl1C@B+!F_31Xu-^#ttbi6XD(2)-> z7g}0~W(pY!3t$=#j@oIMY56N;!{oUxS9aOf99~_}RT^_wVeSP1O&al?w2~CX$Q4=z zFpAivvdI9T7L}X24jq7<&*0REw@-NA&HW|?AU=67h%?>v2tPd(r_(d7ofl^>!}>h+ zS9K1GC0bLM67@6lhvhTgLdJLBtQ{@u8X78_8{BUnUs}nvuKxMsQF|ZJ6+IzH;76px zl(RUCVd6(yW&le9sXD)b+bVv)EloiD)|tKm^5mbE4`|w80KRz z5(VC`9?ylX#TORD#TR(R-H$1Rm)-t6nOQmQ*UJ#``QYd{L9K=`Ubz@{-}<$T$4vt^ zkFBkBFneE_Bm^(Xq?ozqdIkDjCh3CV@3ggRInLwMocpDj`;~F$Lok^7y`~A>SAc<~ zknu16)Y^}h>Z6KeR%pk;s*#u7M5VP%N&U7#ir-7rz&LkJ*PMPHNDUSqnpI1}}^Y+bHhy?Q#x$mD3SDhL-bn zbIG-Ibk(^^E@h&RRU|tNBi|+GM|5qfbxjA{%V&UUv4@P>CQp*rQ=Um|jEfq4ZeO#^ zcFo_rD%z5XWp7k}3=7$F#7$R1%R#g$&SD}s$W44x8t9xpL@c%T5m&u*5uc^nnWozw zx=%lkaKuv|w-Z;2u5t|T{!(i=v=zSGP`1~!W#%zta~t5S4Z3pKhzLBBeq$gMZ$ff0 z3|BNh3MO8vcKxeU7Cidiw$u4xT_%}886qpAfBX3K^Rpr@``dl-GhwKU2Bn5}U!24x z6WpKN2I$aUQy0yPrPtlIQ)k1XE8-*Y3{ftIK4B~c4K4}y6LOGXKFT(S-1Mw$-Ickj%gF-%QjOyCi-nqxjm^#2R^#?V z)`Bmhz)%##V&10dhfQIzS)SqP+e?ROMM3&R9nFri4}<&VzWx9n?{_jrWC@N`-|xDnt9pI9WPspY|_@pD>dUm1Y|(EV~R0 zq1|rYpzqroQ|n6iSZ02_W1c1VWvw5VW>SOwBBFKtRO@A%nQg~(xo@KzE_p=c#4Zqf zj71^vHpEnH@|PeILX_Yy$5=Rd-1F(vr>5gg;a#RBQ4c4}=LFb!2tVcb;1Q3bkCS;P zt(VsQSTwS-5zFAEyuNDm&E~D$ir1RsC7WmLe^#4Pk;E4(@O}0?msLnOzVZh8ln*8s ztaG@yw1kB|9h>q(pY90SjHE9tEg6^TLY0!?%_dj#F>9rh3Iop4?S*+)-{Rte8VWR# zDb21vOT_jMT_KBKV&^#qqq*fse>Ta_zQ?kYD*CzVp$_wSO1aPiBcZ+?!;(KMca{JZvrgY`%ZX|sr^4yra;${~<;Tq#;E?#scP~qgr>pjc` z!4r#dnS7jF?XSAxN2KmICK^vRtM+u$Pcm5F&tspJm}Kwks!U4wGH%9SoP_#;sxQ3j zT@Swevy+@t`1pfXlD_e*Os~q3)Dt&w9hN<03Vt=0r4Lt$HMlG?P|YyGT`lrx~6UH}++0gQ5L&12nkbu*XpC)GY6}?75ZZ7-iY4 z+0lNPD43kMA-Kff)!`=oK)oj9{vs>Z}Xst2SbP%y5NZR}PNTJ#CSJ2DtPArV~@UCW%Hm$sZud6mrQUhL6v++h(`=uW7=zZ52MkiC?%}l;D=E zY^or{4KL{ovN(fhP>jYX=r`@@4KQ7wM&A#&-bQYOjNC^*3~fn2V29ExKkSSTnN5#b zm)i02x2^Rh&Q+rv3D@5joQ~u)#D#*NCOFt~vpada9_%CV ziGM%x2l{vb(g=P;fv>yg1qs5Q!ApuS8{#OmER!S=MNk8qc5~ zBU`sci#}X$papH&4zi(mW$RZ=b%FnI{#B7I3pr;&@v|hhqu%@WF535^5lXBBZ>9OS zm%AK7XMLV~YRo{C_?YNH0=``-1} z!}1hl*Vo=FpNqe`g(&bwj?3b_lHji=ez!B^hCv|rJzDFz8Ht$-zyz7YjbO>i+Bn2@ z03P*Y&U&QqN>|_A;9*H2;|=>N_ZqvGmF~k^FB)4qQLUQH^4@YurkLwRhS|0S>^3>QH+E<0zJeS0 z&kOB^w^N1T5Lf`D!^Eido2l19msL{dBb-3bf9bq7Xh@kjb@8NvQ)-Y_9hUwVhT6$- z?zWD>Z3=5(GWOwzG#1O`xe&klyS5*%q9wL!=p+tYTSk$qO)KO9>OLH8q$&hqre=g(3r;*mQBA31# zk(625_c(q&y30eZ#Uv$-Tf z0@Pxh%@wZ8?o4Kyq|6a>Et=-Ka+cYP$`M`b&M6e>nAq5AMw2JvR`|v zWEUM%!m>@&`BlTmXSk=C;ESdiyITiyfYC7?keDLr>do|Yf%@FjS_43><)A5PNHLJG z=h^T}@01s6VJH$-pA>H|wvno)y?sNJobA(4V{Mj>&$DBaa1-a7mGC0|XA|3r+*xkd z5Y%=~koP48W#R~ZBpH`#@`El$_|aSaSWK@u|`-`L{-8 z;wZyZoSxbjijZ+azWY7>+|^IUdB(uKF}~Hdzhujgu?C%;l=?jCvS(Z#A;_&C$HJk& zB2~BF!`mGRBPrnhPQBH9F?`XycU`u3(}He%`mpCYBfiyKuBsUBT;5AT^m?53MV{A6 zpsxa1kn)*EZFbBV>+-ccngq@AJwV$FlJZgKmJt8TD@9D!O}LtoYWb5V$1|AN;d%^& zshpw5*!fzV=>P+xVpFla-;|zEb{*?(CpLBv7N%K0(ZS1KUrMF^F1*LkV9gCWFy?pR z9Bw$q&R&0g!#Ap*s@)WNUAk{0$^k|j)n6Zu+}B7|81keT+vau^`eeBQHS5XMdAG3D ze3Dfaa|;c=r@V^Om)Oc06})lqP(>h6M=iXL^k}%dZw7d)lQ%+4ia* zdtuv-93?1C+pJ2>ye$9ELr-Z&z?9kgi_DiL58~+>d&Vy%9s&s zumxnts4DG?qq@9HI%ZDfk0BNcCTw3>t#Qq`bo>X^2(^um^Z|md^ts5O9KFJ53Z$(& z*$w$U@0MqSlWv!*;}qiG2Ra$7Y3N9Jz3M6_;|g(L&MRIH8^r*Ik!rUuswzkQKcd5x zb1B|N^d>H{4lbul#!nuYEX)hqe+Rcjcw}=Qg5Ag2HpkDH7e~z>{#KNkugiWBkRMH zQxPGJW!}qYwfA4Q>mv~S@p`+*kdEx(V%U@Ey_xzGN)CPDvzbLldQ8Dc1~XHbyn-&_ z^fLE}kT3(TAD=l9Vm1_wsX&y&uZJS@R}8kZ@80PDjqea}8HLL#73Wi=DIHG5MR{;t zr0Hh$goxX@#%f`Q0r-V*kp4FV@(HKEZ1PP5I%(hIh)CAY8=9yXJ{yvIN$opK&uOo& zC8Uw z-SV?8aAN&(!ySU>i3(%24U1R$7ScX6_+MWRrzrneeg0CgTf!CxSGZr=*tIdjX{%Ts z8DzXt+GG4^Hr4-`jmn_3-{ETZYzBEU)8AjwM)ah`D%v*MhVGSF8rgL`4`Up4)*i5_ z$ZR%zJXa-%gF2ik}_I>$g@Hc&G{GSgs{%*H#Pu^;M z!PkD;qwQg({Lc2S+U>VxE6*9P-fm&Sm|sGR#s(K3^zQ9+hG?vh4^BQ62@XG^%rv{= zz3^*ho{A!Uy%0#{Ln@VagS?hEm0o2|x=f~sek1RBZ4)%Mn`J$I!Uq!~e_33W zC=a7HQFd)3*yZqKU*5s*>_F!Ab5_MfDN`tB`5mMHpQy5N->R|J3Elsz=hDmBo}XzC ziRXCV{cKMvv@+p+U!)*_4-|fZzP`LEYrYS@X}NbkVhG4G^}x%&-j@_0i@ju&8GR0; zFMb}|t6P$z5x*HiDg=LLUi#VsKFrn0&0$_H582u^@g zF-3*V3=~x|e60z!dsMLw#OF#O&Hf)QyNOR{#HulP}K_+;l%FzsIf6WV>zpR-_v z^r{Ikv4mrscOeA9bP;l}2+TDcEGx~)8FoNoHeK8Z7>lx}&oQ@P&nju;Kg?d8@j6w` z>>-BMRk>b8PRAKBrEtv&5ZXrZS9XV0>kzW51@5$p8H;FVy#jaEl9E$5;7vter0?g<@9j5Ytdb^aSUU0FH9rX#0n%xhb|ki*Gu8Ux|bF9S0pt zA@Q;J&3OCzc~(y$q(3m4Pm#1+$)9w?)Fu4N%ifi0_F_QNj!w>j-t8$#jDS@=%muJ+ zOogrSY-sQqkI+XBvA-D%@s&OLRdoqVFuTDG15$!8+bl&++SH<#q><4@JIQuWMa@(L z{+Uw7lLxr@6jYn6i$HOX_B{cIWw=LoU+O>FJTXTj!5BevL$rJP*Go2$wTW$|9_JcB z&{z$fOWoL~0}fyqx*6TAZ%1cq<4>g>8t{4D(Axz;!AQnI$wBR+_DZ9$QLfTtC@+fx zKTKVYupbf>?x$?CnA9FS9fSqo!z9Il>*%Sw#5@)TWZ%SIy?S3mElYySi#<*DE|ZX5 z;xFU(YsGE&=%-(mJe`&Xz1S({oC)8NZ?#@j6M1Mt7$@~bAVCm7-uvu}`|ajvsmsTT zZha~p_XzaUOb|P;x3Gz3+>l%9gWF4-&<;&Zgg}pBzg59*JYDiRd(wNn$2^;3N8qC(x)XA0GHG)j_!Kq! zZ*J~;%Exri>(AyPR#C>@U+Vao$zif`a-k6hVGV)`n>3Vq9N$kQxmmJn;uVyU{vcq- zDGUmxWRs0b8R1iqO2dsHT`ckiblS1Cll$XQ`}->?9&5N5Jd#|jdJ&^i<$9Ud5mX`e zGet?rP%Qu|ZN1ux@xsP{HJ@7K zl=g+Tk_>yX&tuBx*^@jsT~|x#-w#}i!G-2wO-xDmwbqUs`zAmz>EDrdp;<3q|7N^K z2o4b*OwmPrW3xgxV;ylU^NftRl-vv16@Kic?t~$;R7B0UB}7VE zMy(cEgMe*Fe*sHeYk_^Q*t>7|!hk&ON{Xx*dFViC)%6iwkN zL^vV_m)iBhEO}64mt~aI%`)!!9qXH%Xqia4_=j1_kMRGLOrF-s|EZqAi}Wx!v#eTk-Zk`e04Z zsf*10q(-fyH}OxE5}M>-L$2hsoL$gV>Nw-%pQ~B!Me3xK34F$96rzg-J~%ia{h3bX zgN@ZwU(s4cfD8x9emNY?W4Z0R62d{&m*nm}xQK&^h z^;gS21Q(XdO4X|{iJhQar2oq*CbLPJKnV1yrSXS>a4PcyV$<3i+|aY>quC1EvOtbWe0fE?T|T9*ik zxChFe!ZFvKxeSkq!#nv#h8ym08>$^)Bo6Q`4e5y*!L8f#SZ1q7jdoO6FKKm_wh8vm z5Uv&*6LZ3rw4h$Q=`mJx8ud;j+Zh%H3fcv{oin|}efZ6LKe1I?r+#kn;n6qL;cob8{@s+EXZ!PZKmp6SFN##982b6pxeaNhOf>K{ zdw!{+3nP6Zdz=Fw10UuwgJmnNQaLFX2gQ)7aSH|$Fo@bm#C)&r!5X?^OlK@oIv|ih zZTc0J5;=a=Hp1XfLiVCOZNH14@XR*0bM3}6F~%99HIV?#u0{$H(Ea zU}S8 zI$^4W5jRkC|AEyRSrHu!J{Ko6EXgB|=5Oc#d(2$fXFwSV2eMy>Z(1Z!2$vf0@sw#x;CKAl>JSX(u z_965G0Ji~z{xiNVXzJ8lQ| zMx*~x2o>5dVHT)2Z(9-B;XO+H@lE6;dsshB*ac$@xmCXZ4W=5R(yh{efrojkBH6+- za-#83$G?VD`;j%6d-)+%u(}|?BGsBtCF=P+dr;Yw#Xf2Fo&;}JZGry7DBE zOQ}#HR?$syoM3Y$4~33ro7gm#j5^_0jaOGRm|CkP%heUQmY7ILa3VhNqYSh|e>2lI zY(Q2}A)6S*xAB5G;aJgLK+R3|;|>;B56BRfqg;6{7Xt!|Ig_p2WJ2Dl$9Q4+Z0 zSFvrrJ!Htvq@wZgKNLB8t?`V;xdB)HB_N`NvD&zlfODO+7&0a}&Xt3;hFS5)+adzh;{LJyG z0Aaf$dto_tvq4y*N7l>@H2xn0d#UWBno>@gI?n;^gvbm8Wp zM(`N#!-TK%MWem+zh9$L(WanTO(pbVa+APxMgJTXRln$Zk`dW;}?vpX^6oCHp>QGWb7J@Es> zzrO&i01=*MetekJ0(^7r|AUmY<3>ajdv~pCGh%SdY$~BP{C-pDwG$|^J2LIMa6-Pj zUpj+a?G3%6VlN2@`owi|`neqs#FB(`+kQ9i39B^h{czj6Gfghheg#;!#_5#c%;(SG zNJ4);E+1^(K^jOX=2{^a{uqS{TNDhC!-p9cqoFV->T=r~S}ft2qnjB7ME+94jh7>; z(ol+xVVnFmA;uh3Ni5A65u(YN+eY3S)0L7E8~6SAEuN~0dgE?j(O1?_UTMwoO(8Me z091bwFfPJBpObr-ofd{)kmxv??eROx^v-x@XkIZHqn#GU@_YO&DyFHo-_h;~iBl90 z)blyQM6S6oLjonEyauL0&bm(u&`3V}%^67xGPkP!L7IE92Gaf^l%_x_6JtOKmH&1d zJ8H%HRsKg)U&y$PCWcONFd4Nn%jV{(hHD)* z0w}+)O5UaIQHA4l{&KO_rxxg?{2Nqm6_`e2zKG9E3IhP1sm|As7`{>(G!K$97S%d= z-B!Z2GHd0xCh{*$eDJH#P8JSp4c@;$=QY|=qMK~t9lgMmz+X@l@kYL8P`mP!HmkP_ z0RRKjoQvww&aa~Z4pTyMpy5aHhdjzJiiTd_lFM*W;;F zLOXpsq(c{s-oLQK%Zf9l>`aC&*+VxTKx4mG*#MwGtvGx+4C`Y~i%|M%8=OLBE=5X3 z2&Eaok`VCW<3Eu#13TUH)FIkH0H&nc%uSDl<>#Gl{y@DP>OdYD9_F}&Ys+ct7YI#v z1IY>TY0Di+vK^Wbm0}RxOm5x;GB+X$6`asHFi4730ju;Q@Rr7eHRH-FgECIkafnD5 z>1v|puK2tl8z?9~E|?Zw`u@Bj=Kn@0sJdIG9+b7}ZMyvs~xg^4Qj0QUe1I|Jny{*I5KoxlP?GZuEk8n9xh>X@e4CcB z_FqW4$t9IKLICL}zec=A^}a@v);;lG4bDE{-bzu(LrbDiX9icHzc4ZR#gE|6$vNj9 zi+?}=vtY&VpYJePP4U3bHNtYC(4YfWP!!?n(-ci}X2Kt%Ks6VUVZsaJJGJK^cOLo` zFu%X~Ac^)ONeC*#$Bh^e#n?t6)PeE-yKR+-Wx+SKq}yaA z5(J#a3Y*&sE(cWi^;V~wX8#P2)gs>bU~u@-wj_c`%Y7UKjphF+J~6Y?j1J` z=X~i~zUtB3jr?OYN+VHDr>0Ekf2^TqzN#t#?ppRNm8lF)&c7&Ge0ustS@#4o-3fzL zurYL#?&4TTXcB5q)3x1H^ij)50Id~kkY&C3iuGh6^m+U}AJF@Nw$^)_R*!vJX|yMn zNcE~X7;}VC^Vf19^rQb{@-bc=10}_fL1QBbwRSD}3`4LBMTdW?d=l{r>gxdmoQ7YO zh>mB(f)_W`FeN}3nEs&W!GI13$_grFX>J|e28&7|Y2t$#${TN`{V}ji<9?nT@!rI` z{B_ZEvZbE!2|Z<8-_!j6pg-@D_tZ0`o0$<}QA^{y12V5KpVSM`=rfx|Mk!>ck&Eb; zn!_kSx?X%q{T0LF1Tx7u4`evT85TIismZ7pt2yX?{8t47{H@Ju(^!B z)7V7@Rz*(|ej^`e&MsHk_j)U>+BPRr>{krD34^1}qZsEd*DS~H4&`~q&lQ)#*65tibKu!71(j|y(L*;%I;$OD^kN9aQ#eATs- zcm`d97bb8Tn3b*;d4dCT4)k~sj{u|1P!6~?TL2iv%GJ-xee=T7VXEPE&P~5hAd0K7 zQ6LoT=f(!a%<2Jo0wD>JlvE6jvmyk39T=cU{&%SlH<=ID;SJO5o*0iD7^*KvS%_z{ zAtpi%r{$LEFKe%Y<$b6ud{Dh(Cy+794d{++_pK#2EW4Et&xg{>@Ev!2QPXE(5dbg( z?zbI%TfA%R=AZkASVthC-|<90)_v;;=2O>DEk_*0lexae^WbpTH2v<=Q|OyWq!JrI zb(lgzd0OzjTVX(Uo~AVB|7ihKh%9uUU6Ax7dJrn`{=!7li+=Y-M~V9$I=0@`{uxpS zdJvT+0JnpJf?|@hsq9f4=KwxGC^^nk>qtzjoC9?74qVnt;eHq6;IicAi|l+-KM+s0O(jy&(XtR5;FqDG<`~pot&f%Pe33L= z1$)!3qbe*3?UGRAm>_Mkl!S(;FxtN4Eaxc-= zs&|bsVR%Y_D8Qr|huzi#mSLKnlbKKfeHiLGQWmYug@uEQ+%o8&m<|up{SZqUAU4S9 zAuwk`A9F*MUYt~6?RaMnP$<9#H2ot;)L8TRKm4M;v0wY;f4_Ba``vGCZ4-*DI!1#tqE3mjpfCes=e#yi5TP&-kuV!V8)R6}E_>&lbI>+cL^KP? zAUd_c5HgamH>5RIWDR=&L2PUQT0^9rg{$5>1^_S!2895G!63AR9${t;686rsNaxtG zr!w|Hrsfi>&j#=+$JDA1T)Rdxn-)+|AK&z4BrnKg+6M3L`lb2lOh#cs=@x3Hc#x>o> zI7@~Ky)`PFkO@#u3g$3@wSYd?1W5!xMug7$6c_*iSRILCjIkTD4S?PBuDq8s^X18% z?LCy0=S^$G3nDsUR^AqNu)>f6B%B#iHP6HijU7O1jq`OP51{v~Eu1P-gBMMp>Dwkm zOK1o^i;H+UGpNo{R)=u_j|n?viSyb60EB{oPFMttK^<(y42WU?9JBMDfc93s2m^}u zti3VTkTJ$K%~dC^N`CmwU-|vbqu2{<5G|2cBF8Lx$JU@@*>!B=zLj3kdu>~nwlxF+ z>{|p&umWgo!_2^5r-l*$Du@DrVAne`#(QrKA+q<}J8ulljIo4>upUq!U>MoYzF7Y&6De{SIPd$hnv)HwYkI?@Vh~y-S>$SrDPIhKQP`x$b2*TzmzY z>{8nVgoj|yJk}jO4iu)5q#7BF$|%H21+3vNmi(7nFAUUBDSsHVQ5dW$Mb|iCg@v^U zSTVvNgenu{u;=Lm199al_?`fx4-rG0 zJc_6jxfKyhS_rWo9coX-;Wn{(KtfGmfHlc2i8)c0ix0C;VkD5;&(XAN5P9q{9v~nI} zz7PO(c$jxA0$!xCMmsDB01P^jSh$affD8!G5~9(4-F1qov^wbrLEk3o>cf}-`P;czU0^U{N`0JC&DE6uZW4iJpKWkj;=tew63j@QHI{ye$DIo@3@ zH#TO@yS8Z*V|3b?C2-ESjfvg)VeI_8^Mqd8{|V8sF@)@#0Q8RA)*281u>>~c@cmC5y#>R)=MZYQQMf^&e_npk6rH@3(kkl zRvJT|JtKNAJ^T5pXJ+R;h_p?kd!yK*li!5RzKFtB2TX_i=4MIrXi8&WE0Y}3v* zHW#~jn&N$5xgX8>?ad9>Ij#L`48@@(X~Ri?`!1RG|CyT=e!n7B0ytJ+q8{s zX4}V(9y#)R|MowWuK3`GKJ@MHeD&zo_WAk3Anh)?BQvZ1Uv?}Y#u$UB>4m7CgsmZh zk^(Sm?W*rvB0?Y#U`fMX9rLE8nLz;38lV|zz7H0i^DKLvGb;Z|7}H}6^(-a^qn2>P z8f&mI zJO0Rn)mbsw!PvwI567C>R=>9jgQz9W6idozV22p@p)Uo}FzrKc0K~p%fc^4^>DJ)O z00rv;nX%fCaYi_7naDC=C~XM~w9>&-Pq@K5Br@mc^Q$&yr}laPYzzt`5OOSe2))j+ z#za6=1k2t*D7pxAm5&7(apnvGvi677o+{>g2Uy8Nz^k~R-r9^{+g!{lKX`-33Wl(TH1XNW_<)r~m-ihMW((Qg{!I1*84? zO6fEL@Sw6DBD5y7=*&CE9vHx&il!l_7%-egQ0re5>X;B6dx<-K#I6`21o0eu2PBVb z3t-9uy49dlW=w=2&^FXqgNW8P*Bw9pwb~EA_wWC7^CP$j&>|X?2EmH}fpfwLo#zc>ETPWOJ~}gJ7X99;$CPyR zenYph2SJ3+c_9?Qt%f?sp1o(W2%4uP0s-il(V*{H$3SqHY=?%Rcg}e-2Gys`Zn5n8 z-aGF#-P_J=V~hZ{ZTpH>-1KMgx6gMmne4^e#0U?^7Q52SIuKvv<*I@fS;wke$&sF& zyOH9vhX2ZE#Y#!o7X$Sds%EbN864`OTmoTag^9``At@cS#@eQxZ7%0Sv}U*M|DvIWET~-p429#8&20Cyn_${#B zP-hcK@L;Y^`W6Ud5YQmx!`jw_?BJ2(H=caiKr$O zUc?X~fjCcHJa(v<{TnwH6iD`^Xvf}vj|#) z!m?>isI?M75YMvNm{~&x(Fky^ygv62jqgBiob%6QDhHbap1b_K}05~jaT zP(XPEawvih<=rgcW3xc2F%8wbX#h}>D^&Nz9)JXgz=b#*Xrbq@;Q%54G#1;|Hm0#{ zbL9Bd_kH#8bw51t?Z=EgZ>_Z=z2n}CA%rm8OAta&VUc+a$xK2phJab|QX$YpYTKCL zNtgDSEkp!DFsPM{(0T7z0Kpj4W;;V@35+nQ{HTEm2ne)|0TJgsfoRXAR>61(PVk=N z=6$^C9J4en0l-FUc8+WyG#gtx*Ia$w6OW!+cg4ql?8m?Q<-Z^zV75eiE7usZM4I<) z4R&7J_QOn>#)etuh|)GzyeGug=ms4yvpSg$wpybnd)I5UAV%x65Cp&y7{b<|CD`rU z+<8DC!dYuH^4M&x0ckLn4yjhovb{Ca%~NIu0a5dR)}jmZ)xfcYK3b5)s`Jjb8wQa! zX6D3+Bc9FX(Q9tH{)TUV>(Lj!piK56?Eh!)O`jyYt~;@F&RyQi%vyT|8XGABT(A%z zL4Y7RBth&FDUu>7aU_c)X(Vfx#u2u|{tNugVTbJqhpi8G*q*T*lt(kN#*$`akrc&! z0SSQE2x3P!&|6hkRW9${d(ZKQ`+EG?dc7j|9KGkHX-iurGoQjl5YxZ}jAtdiLRWH%T-?Cr~$)sq#8HRSiv!OpDw}c(aZV zN#nYNc0PD@93LV|-QBTD+iQ|>YkNWk-gd`hKYVgl505|cw6Z&lvTx8EONpn4GlQ@pXn6eC zc}18TWi`dB9<5M9Ab?myf*`2Kd5$eh8Kfv3f)E0rls;rug}}~NBgl}@hcKFy%t8tg zpr7kru9eD3XRCV;ee0`_o_WVu$iLxOZlp>|HHa71KMmzI?@VRGRX4zDV zNWcfW7qK%w9RtTO#L`$^X z(_15_6rqS!=tV41$t)tOMs7u@o4HOgpA)O%$e1J&pPV=*1XB--mCGZ}2OmQHS6D=<2C6}bz*?0Vz0~WI z$<_~C^`+B01Mj*2z9%1lL}|37)&_QSSX!e=q-T_8&NY>uQN(D{gi#fS&?pQn3emF| zg|Vn#6CsFJBp^Ezr-^!o>YGDiL!78a=K~hZ{NNvUU}i@S$B+uTqIcl z;ckj6tTq$j&AF*|QF7{Te~p8M{7;>kw_nf5H2unZNyaV&&Q0!x|>B-l{4hR#MTtY@e< z=-3zoRIi=u-1jC2zgb7xlO~Q$@PV0yplYAiD8WZ6EE1YdqRdcF%cut)2m)l5lrp_M z12l)OICSjj4xC=Dxo-XF@neHbYgD~l4JR(@xA05^nW8dC%?DQ$Xd>uao*-h1o&9)Ik|r_;l;&%9#tq4R!_8$?=P$xjU@ zam}OB8--S*V^InVA9_|7E?7%~7?^$VF$fylQpBid{KT!Mrqo76JPQC@tw7kvyqnlF z7Lf&<4;+{Xt;U!mYK$IDoM+w~xl!qt4E2n%BnluS+$mfUc;bAoXKM#+V?$Iv66ZW9 z)LQj(tyF(ybzLtXeB@hm0;LPNWU>IlU6$Swc{gc#TQxDRv|^&0EuR!qG-#L5zLXwL zKY}K)B#lC*JaEbrT5b8s!=_zK;~!08n*cQ_jGjQESTSw0e6TXw=9$&E^8B+$7&lST zK&!f9jC^2Sk70^xsp`S&VXzU0Yrw1XXsQ@x-JPypRL$WM2WV?N)bCTLga!_g5=GdE zV=H2u43ab%7Ouw2RUX&s&7)IM5r)9)%eg|-3bf9$<$cdTvw7xAVrx@SZ7U@MZHwRs zxmAiLrOP!%))@(L8D}=Bn3@;@iwmL&qD~0FP~>Vth>EIfq^d*&ECW-$b^wSki1VbF zITFf9?hEHf6Hf?$P?X*ff{4)sB1GT=X9{EDN?>*&M2jId0}4JUMF64{IUf$J4~$Zp zgmk|5(Dh&b>u;P{6(9f9FFf`14~V31vWY9#mU@UZF5R-#!@{#j&rmFE$TO2!B_c)X zm?1D2!qSHztPpaeda=$O(L|;$5*@{aP8S=$f>>Z8NEiYuqB?OV>|g5*@?K^rV0PWrZ+ZT?IWgmf zTrybz;Vw%#(Z&|SzKO4ON*JJdrjsbsNoq-WVVfjV{|h9b*kr+UK(8Y_b5Li~S6|7X zi6$?lJ6t%^Om^!Gn19dWLy+UZ}|LPzhU^-T*G8U@BIN?gE-p9T)F;4^=7S`;f3bCJS zCNN6(`zwd8xcb#sx6Z1H+irXNOE0|`AoR6m;1GmVHI-@XLKeG|5mpm+3F}G*WM;>l zRT-fY%L;3MZ__;hL8>U1fB+&lGxJ1Zt_O!I(&>Ew0gVy^gfZ?&0I{xsMG!cC1S97` zSQ9!Qv_gT{Z(Fpc*wwn9ncOPUI?wvlTYun_zxbVh`1YCg@bnYU^#%ny@7U+cco9S- zWhUPD@~m_Y0CTHiGaW$GilQSyA(bu!=G-WwC_;NIR*F_aU?Gs$Wz-PFwxvWA02r$= zOh_29kXd|?(s^bvAQlAx3KxuuerYUyC_~WEm=GzLy$_jI-ZK$k{n;6#tkyn+rA%w9 zknHl>zHIHP?|%J>v)>*IxtOv5!rhmZ^hSXo#`qczrxqp$qeg+ zmv-zP088b6YI;0kvQp|UylI3MnNtjR#r#8xSvFOZ=vWOX)u1A1vV+oDyG#fu5}383 zDo9CnF*~BLtn{tc3P`N!>D5C&dGgq~ToSJy8H(D>GJHFqwjw2 zD@I}Iy+LAt+-k?*oX@RhL<>^-U^RIk#)Xd#UQM7u6k_b#Csmn9doSb)xvD)C1}LI~ zSdsIg@H{U3*abq&t06~BOi@<}PF`D9);R9_0IYRpvZXuj{P2&TeEu9&@teQ*#}EJDt0J5MvS1L% ztRA}n%!J?=RP9V}rq9NdMNOy`j0$fRHkq-p1BNb_ z+>3tKiX!@0$jHI@U@8<4O<4bF&{mOBAxLc*06Zud_5vz$yO_EvRbzA%HVU=EN$E08p`!Z&C;|{$ z_QVxNXK7UdA~7&5W$A(0D9o%G#UVvJh8h+DxE{#jw&)M$@{?+}nrAA$-&nP8?b((1Gid{EU(@JY?v;M}3*Vn!1lb`+U zQ;$FF*!PIy#!ZMm1ghqw3&!*ih)q1A*RzWJ#a$jNFD6%sAtKel@mdFQNljz0Ccs#Y z++%6lszJ>W34ueXA+T{;V@#fOft&19M6gCF1SDJ*3+= zJo1hk4sC6p+#Z+fxhVn)2dk;{Y!CvA6F?Dbb(NbMTf@|i&NV{e89)?*^HmmZ8Mug3 z5?b!afg>JpoaGdwgD!9^>;Vx?pg=TAZ1`yvI_F~_H3Cpn1#TS+i%fi__L%b9&rN2@ z2RXEV1ppY7$=C0H=riB{&JWLB6~~STm5p+vPL0YvJzFvmaBlUe@B@vcC?EoJX0?jV z<$x40hfsPpT3LdL3!Ygknv~8EMi29-a9rC%2;h8hLE=dH=xL7wbqg0z7=?v7Q)Ezb zg_@8NEn!)f2(e#}XhHx{M4qJ#%tQiGIv@L+FZD8OX*71%Ub(j83dDZCa^<7neeQML z9SgZgg16uPiQPVjg#ZBTJqSA|k8o(pk(<;utV^e>Zpl#hnr>1;s$6=U%6WtiV0D6y zGg&vYbrT81Le~*GT?2vjaEaO}8tI_1y{)aK^H9aw`l+3*jj{~O)|OoLOLIPGq)>O- zCaeZGCZ1$83IQ;lbTjp$?h015M5#t8wT;S}QN4n786wwEks1ip{2hR12t!O1};1_4;kb$s3jiBa2#lnkJVP{1))={#}d9zg7S&Mb9ZAYjae1pt8{9A_m0h^~et zOAJM7ML{I6OgsakCW@9vFSClI-?K#6%j~J~Xmxqt6>odbH@|W|1#`W@VJ$3ymU9c5 zqMLE&)M$_!FPK}+0KW7=WD*1!oDU-41@?FsCS`mtj9mi67FW@2C zSZuWlA=s+#cC;`!)>1Nv4_pcmfs%@atGcs%%v#zQmzmXs6jO_r`&p(@8Ev%6j2%n4 zXXViKH-G4hfBM(wp^AlEa9J?I%SFaRSXwo~O_~WobxNP4fFx7oZz^*}rd*;O!@Z3%*nRj$P5V9L@*}ER8CQ)w9R@;>%-F&4xU*ilRV(5o>jw%%QeOE28iHX zh~r@up@77;j}5Pj^8v6ftH8P_1nVgiQukA-Q)B9es5Kp|m|u*FHBD1R;xLAG?btNG zj!mnZAycRjtx<$v6lHl&nxtC>`76F^-&8>+wgqnK2OdDe1NfDG*hCm^Nz?*%#gOU7usA# zHwA*p+`#5h{k^RSeq}yPAz=%FO`AtWb!c$q*c)i0kFr+siA+-nkQ+q`6%i7Y zWr(v0mBKpJL7189ydob&n46X}t*#(aytV`~Rz$>ZSb>?Vywga?*>mM0^USfJoT`?d z&=5le@hnKF6%m0ZjHLp3W;so|YwX-8 zimG6qcn>0uxo}=949u2LM2w<14LGW9eXtxGaG1@{+R5 zv)oDWSbI4;Eu=fSolSsaD)={@L0V&9)Bda52&@SK&f$NlbP5Kmu@aTnHc60CN*QbO z!HMJM4XT1*oy=D7p&C`A$opWeYI0cG2xgrzL{(a86>1I5LL0S!AWEH26Z?S*B9I7G zli=G%+EDXIs#9U30(@Pe5wrP~LZbKr0sx~l8M4|0@Y)P+xZ&Mj`MZbTh#r3M-ACSg z`%RmhM|MUtI~M$8BeRjp5?j{J$ps0=I;ht|gN^a2o5SA3AM4@lU{G!SS)Bw`7JJQt&kF(QI? z-?PsQ-{2*2a)WNZVSQYbTRWrm)uj+TB2Eft4H_K_87PDhNn4%Nin+#IQ!MjjmSN#Z zQPp@T&Lu&#Mj4|tq7T7&PedAVNmHf>0a*ZuMlLwdr4J{E1)^kHSw)Ia5sJvz1rY(3 zjfvBm`aP=%bEEUz2KFocp3bvzD07>s<*Uy0!h7J}Qfz>uxet{}*NsAw=4mHbbo@#tZw{FovTyHMUi&jELwe zjBzzx&8-EloQk!h6@aRuNz`%Z9idX1G%ocr25+3*pEz%|Qbd5*t7azw15SJhAOtuG!3!%yYcwg)NY)w<(ORqAo)jM zIN!@nW_5D|MC+k+fmybOWAB4=UJ2(EL(YIAE(9OA^qd=IjAp>4OyyQ5|y+WETec2i0*^+(PYy_4w&%}k#rH3qBf7*v|H)><2L;ZQINhgF;Hl%>~N zYfUH^vm6y+j0<9HCmk9Bm$Zfhh&9g9ecB}C)|G-)_%Kv1&}tGzU{+L3fNDr#{M}fi z1_+uE1d+&UMTkUTj6zhTvDeE4IPc{Lue#}xAG~~_^l1Ux8yLEE81C=L#Q&r7r`QflJRWgv`V~ zD-g40T&RXL#a`SDq6nEGR?Qnl_4QzNMk|9s@Dr8ofBB_3BS+3#4!`E#{jUAPa(L|c z*7a|>VsmS(h%}-vy|u{Lp_!&1ol1vvj)%r zKJa!?4omL>Pdrata3S=pMuZ?N%t|XCVq-Z5k`TZ_bjU-VSyI?DMjHiyT4~)gS`h?q zm#=;7(M3bi%TX3Uc$tdx{X8!@gq9RGxuFR4a}_=8GR4M%(P6ar2gA!f@sYJ zNvkR_c=BZLjjVdEgs__B+ePWEvDOkWAfopH5p|W+C(ZcZCOa1EITb;eK_U*s0AJO1 zMdAcIh#0RFDMXb}K&d-cN5xasvILZhR1l3KBqT(wRI~=NOdEyEgM4-WjgS5C0*}-= zagwgS$`Ije$2P7#bkI3RNLG_CN+gwKIgDj;i((aLC*8#TyO%nmJlAi~%wra2!{m>HwVnoMOT zvmj&?AZe>fN7)J|a`mtGb?c=?L+{r-SMaE*@?Yg*PIVhfCCd$(Dz zoCBYyV~Ne5CWt0~^`%H_Wwh4T+I;!Mi3`aEQwd=e@stlv1Xq`OA%G%`vr<(xHZM-2 zhZwVoXR8$wLDh!3!fv^jGD}2S6G#XENO8OrGa_oO zv_fMv5ooQ9Mx}`qN#I!iA9MXHcQ=Aku^t4h(J=}bOAMW7#}b5x<5DY%y#iIh@4 zuydiG8Bk;l8cjfCa=mYDjimsy|Ji5H-cjiM>NjLtqiD zDH3jKbqxYwj8cZI(t-l0tfjT(K@o~xf8X;jXD>W^5gRD~=#i&(cKX*{sa`pDj03GK zXM$=e*IUC$*0Z@$nbldQV~;ox5J0Oi0LCG-N>fbgi9-fs!DXFxj9MuGh!9AGTB*_p z7eWL`l&XVFjHt#2Z~Z|=3I|%F5~Z!uaOK`LMvvLmPd{}&rIY6_uN@6H-E!k-bmWDX zkM*(~5b|Euw`$^A;79Vx1jfd5VM}vS{o&i9Fl^yA>yZ``Y6dRTT?)gR%g^%UvcD zv+vOUa^Nmw$ z!=3Z>#J(OW%EA7N?A=RZcGFUAl6qPpi)GHu~a-J_;A&0 z8md`Qh`P2g6k$xW6cMW2sqHKwL9|*~W0XQeN+}c|o2jezu1vUGTfg@C7tS2k~NW5lo=KCWwch2@*;vFGMcoa z+*CG$Qj}{FfSqw+wT{{l5JePse<2+7Y?kZH7)>ew08oFqcik1MUPAxCdw=-d7cPMw zUV8E5_ICe+x9)xE*hVofMX0~j&#fw57>_+LTdU(|xjmd9h%s6#9o@fx;JqirJTsHR ziGWgMw6dCdMq6FoGr2WZ(P&bRCS_(!9AH8SMk@djB#+SV=UGoLXPFBnDZ_+oYs)=L zK>a)K{?)(u;=jKHs#wSykws^jH;t?;opi;hX(tAq#LzYawC+F(Fw+HQCjCX`|5M$g zrs-hQO^vCBD=BTX9UQ-C?$9&Hfj!4hp4!Tl?e#LPh`o0{lrC@xTC38B*bPzv03u7p z6l0-92vR!(3EDZk)ljFv3<5C{)}#f+K5dyX+Gr#M;X$UIfYxd-==C#gY`(Pj9pC=e zGnZHoAG`PFr=IxoiQ~fqtE&RIcYWZB$;ne=U%EkVM$S(PF9Mc85tcznDFz6E0iY;c z1U6%J9Ksg@1IMYnp^Qz`2vyZY92HTlyYV9ZJkN5AAV!l`Sa{GDui3M9q8JVahaP+U zOw$%Gl6?A}E57x_<6Ec32Uk~&HLJ_{a5y@#Iqn+;62@L2ur;b@sB}S;@+>i#b}}h_ zU~9EC+C=NYc@DxX&V|x>;Xqgw$B@x+A_s~Xtpeh5KUZ1_aHb3?WWcO%)(82RT~Jp) z_QOSj=$k_pjPOk(McG^5x8&VKsyWwHem_(PDK*5_O`0Uy#8i=l@YN|d32|%yugM6l zkS`X?$KGkiXp?6v2ampXDTv^#49ER<-mqul$0s+pd&YX^<)xk?EPe2$x0<3^fJ9nh z%zLb+26B}k6Nz9lvrs^U6l$eZ6F4L=nov<@tucm(5V>cRQUppXtJap6jTW7)Klu#2 z^2*6euZQQKJG#By|G;~$JaTg5)b9o_7YZO(1PCDr5Ltz}(IQ-yP6B6| z5Wp&>V>>kfVF=7Fu!>G^MOAT#qRc2H3INN4et*zMBCTY(uLKntwX)hfv~O+bi?u6m zd-(giv-Lmu+|H*z|Ic9b-0|(va5xqxq)eva)f3zOyf?54K}sJSGqY&GOrv*B0$YWK zFjJIiRrQl#@qvrdBLOK=ND&2R*sh4Rd2pXJP%&WM>uXed_w+^7<3FL@)HsvAt(0Cv7x^QQ=A-YwaPhl%9iULLtQ5C`35EUF5lmT?681s+dKR z8RY{55E5p2F2L+uzpsReY^E}GV0Eo1cls;We(O7Lpp(#rlRNIZ_Qa7NZk}?4u$<>b z5&9O2BCM@00fG;HQhEf*tuD$i@lqD$WKAt8ayiHX2;Z!-wzBDpVcQY3(}T3> zK-#)WyRg`mwtsiW9U2`%L@`59k9ym-;drTMffazDgh}C7 z2Du>mSX~a)Y$iYqo`Vl85~oHGVl0D05K;t448Va=1T_U_YfzEu=L1HO09PK|JDQA_ z58U+q@BC!9m)?<&-FNG&FMRFfX0fw9UL9o2SQMopv|4FnKoK)D2LuQqXswIFxzbNc z7pE{7rL!znf`C%QfB`75SAbff^GxJ(YXS&SzP@KwiO#LF{exfq=4DqK_lb}0{lPO& z`3X!)cg4Pyt!=k9u%pp9H%7G83X0Oj#-U1)cVRp(w}ul^3IwdRS*Df3IOsUGm0@9F z?qxYDFd__kS@5BBvXrSw z=>fnq5K#yr=6w*M2!uFYHae0C0l*p)U%5Rc%zdx`UX%#})ySg-Cc-Q+s{pbJk z|Jm*3o>qSUzxab^zxKa;_lf5vi1&W~+R}K!nbpMZ9y76;I>r0{~O=g*zM(>Nj~_|8+r4ImyR9Z z*(!UvSsC;QNo(2M99nCQvB5JUkU}50D11@)+V~?~&6@{85@tauoYy7{GSll>?=58p z93I?12m&Mf)^C0Jk=w6t?_g#BVZXAAXb89^G!m>QDal(XBv9XMRpa{l#JE_L= z@}vj=I4%m*(#x`5ufNhCw6vYz=!%fqw&#Gqm7MI z%(C3;X{9rxnpx8k`-P!yP6&b7J9fb{1Vrrh^Yzs|nq5BVpE$mK)l~;3qYcate)a2% zbeNw8SpeZro9tQH2%)T}$ab8h^-J2OrA<7r_Jc+U)THdOHx>TP%DZk{UDsPrzjWC7 z;61xCh=?)DCJ?P+B)t9uqp?+3kJ&ye%%&HCd{>_Qsk1(Xlmxtc?{ zxwW-9Dz4nK9Oo&TO{aGtL*@%kuJ)7B9x?wHv?mH{agv z)x073;QQ46<<%EneQkT}iO^`=9*#LwE%yLK8>5X@q>a+KF#?onR9XoD0|Pke7*zG8E|HQX6G zCZdDeDtF?4EP9mG8s*LC_)Szf>IO< zEet|ghM^Zh$d<1A+y8G-6#r8z3n2VQAs_p>4|;}bd{ONmjRhEA{hM#>_Ss!h`PpCl zrOmBzSvn5UI6zWlj2R5_zx!8zw%ccSN##?2^amT8J4I235Mo;$t#z-LAKbh2r~mbT zx7%lTN#*0e|NGlJ)l~riNMwxe_42pu@BPVt_22IH*)8Ov%K`|0I^{zTd?0#9n~@7s zrS?_IOf%l8>byxx(Kr6~Tf2Gc7gQej!Y{pce{RNf#e)Bhv9ywZ$ci0sYJV?}rU|VYgP^A!)AR#GGM%g?cEMI^9 zHGlTs{P(+h`WI3@{DogXb@HT}jMI|OMnCkNQ1U2>o4!w_uc>di@ULoH!7e0<3D`v*_VpZHkT6!9>hnh2t~Sv zQL2!7+F5m9C?EndXspSX_8d6y)&Ko}-L2&;z4O^`ZJ@A<6Mp)IFx|G2wa;2(wSx1mHINMj-@pV zP>=vMXshz&Jy%@$jX(WYmv~X&S~Q`N_8U5`%-v6sYhIYjm5rFsAMiNR5LQ4(sayNP)5{AFS*> z@SQ*Vzb@$t7jofb0fcW#`Oy7$1@EF46o9eid2*&5KRrq|{dD)Qy3?et!e|u7AR=jF z^|!xt84<*H-}{j;+6FGECOwE!HB$v>CUUetVXoodbfW8Yr;{!svY-GmDj}otrOOQt zZ@&KlH{1kYp!i6L31mtSU7aMV=xqIx`qZUr&j8JLZs3qKntp$M|094uP=}$DEqp>Jwl6`XyNGndRLN{cN#y0{jHo z6EN1CxHSkGIE3^^B2$s$v;ehILamKT6%`yZl8~jWzr63z!+-JTmu$&%yEAj{ga7oGPab|ziXpOV+`@#@ggB*xX=6Q@n=dovDd-qRiMzOtAVxia&UAnE zUANryZ~uq?@ltA_k=sB0+2O`fDaQ~>lo$()5IBQ>=X|rYMv_R1i)kDo5<~_RBtZqF z(e$$A^&kDsUtP4dF608s0tnw6@}c|RA5tP%Z{Tz9YMeE9yD^W`Lh(I9CIN=)q(jRA*>8-zUjW(A-VBph zl!y%4{$TGFkNmq!>M8xF|LGq+`okyvcnhL06d2jVP3cM9TJbkS|kTk9f$!-O2y zH$|Fk49cqB(%vhtezT+${UetJ5WWfI1NXd-gBMQA0Ok?VUj>9*9`2A82Ya&?BP;7dJx4S>iHwb2>V-lnZwDa`P{FI6va-B!R zsL}TKUv{HrHw8GB6I`Acv{n-8$;-#U~3RS zs|Tnus;UTrAPQ|I z{ret#;3wa|xZZ;I{QM_(PP{6`5JDMgaq1+fO(n$Ul1RGC*9h4>OfQq2ms1V?Q%E7N0&_Hbf`#KkE!k z(k2s1RDGLf0~JAxZc=T2^sS54jPdq|?j3I)kL-s~8ZKB(P{Qu^oMQOt6NloD)3Ts6 zX4=t7t&k2c6b2MQMiQ0TrS&Jjda)YU-S%@oH{Li3enL{^#ZVg`ozX^$eP{IsomME0SxtRTgB{5;(tb~(NWya9>VwA)AHU$Lc<+PvOio1 ztewL+!`!-TaGD+`X|^4Op3Y0q`r>g`1pt7x2c3f-4@Ymi^RB~BK5@ZSamxb_l*0{h zZLJ6bbOOc=C+<=^Oz0k-Mw)wL%CeZz2Er_`#_!VJDZxImf z1rT12^1*xW@XiVQx=cQ;2E*ySI>mt08JPHc8V6Aa0-FteI-wk=Z}8J{iM0GeL}dTf z2ajJ+EPU?+ADe8QsJI{ip)_u-WPfWl&;netJ57DHlD;&-w%LtsN@1s0g#ZXJ2Ui}v z{`wOyy>bCnaqB}5PEH*MS8+i?z^D!AZu<4Z+L_n&^&w6xr1_ET`pH3O-=DYpr|M|x z^y?O;>?h;#&)jj>ktd(LfU3CVf&0syQxzACw79YfYR~YDQ#ZxET3>V;2u$=;X%MIG ziL+o~-LkOuEC>j52s=B&TkpB&xgYFKuJuCBAPXS8?BoOYzR$b5Lv*({O84$dcjxwC z4kAJq0z0>MN(4_!2V3cc*J=;q6c%1};P{af7ep2BdEoA1>m-JvsgaA{y zcrF@F#R%IUEy^W|=)4wZUY{rftB@gxh;Z=bfeVL)w?6dXWb;^)AWA5yHBjqh&hFfx zW3q^8Mwnh9P+uNXapLwO>1Z00w{3NS?bX2&LNOj)KrFoFf&0sy%{D=_sTgUIKaJ_N z-)nq~LR~&cjU7=RH!z5a0urlnMhWwMu5GG~NC-RI!&^Ug?*a=iH=*4=frWJBL-)O} zt(ULq;M{&Ob5XFxJ4EUlywp4c-Ho%xjV>K*AEr0=ywj*$g3;`xM`+6c03ZNKL_t&) z4jkM&Z-2)dSH&GacVDr!fg!ex5d@%=x&U_f=jrq9K;R4|?6^&nJ$&kyr`DN1!tT4) zCQ2S5M$H?E3XfA%3a+?qncmZnXG20I|w0$$4niRv$` zzbLt5n){@>r657m`Y)al1uH|AK?1NBU--$+;TN9&+<)>1Z(J1%xqz|&!plp_(n$yn z9ZX#;sh_TqDHNQJdeHP2RcJ`b=FnwT$s0F^-JhvQz40Yj7<};M8^pqoeg2c9jS~=x zv{hJ=-#O=`X13)70;dFF2JYvtZ<-UHo-B8vR!|tlgD)mqCvUm$?$@*QY5Bk}es;KV z4BQx{+4_?xX*X~+gMzJ}wEc~43@z~?bS{V)MC@D;9lu2DZfyhDwLu`r9()-lJ4auB z;pczvKYk;sc<;}DqS)RPKLPg8pkUW7Nu9gh+kxuUR#-^X+!fVV1&Q%zJZOJ~8bECf ziDdmP6t{Y)JGwQt5wI6mxY5=VKYHqo=wTrjTo$g;%Si6{$gL85lOvj#x#_0V!K|sL ztJ|Ft$V-`F`?B~4r(B7N>+5x#b&_gW4*=XiBfox%sdNXfIe7f=dHP5PYXfn0op_oD zpDuOQE!9~Vc5!PaN;uaOJPmrMLC4c$W1B=&xr(_g%eUY8zE_@l<~;Op|8M-Wqc1)$ z#W40xBZv(%t4LT&doa0D(o~uDB5C&SPHe16fWc-DPqC!yGj9(P70mN9PphO#v*ob4 zxpU&hm(D{E0C3mmKD%@Bn3Q7(J}nk(T*MtuN9qV|uqraX>RXF*^)W#MmaX3%J9o>J zeb`<=IOlRpudlQOQ8jl$23g$rJTnr?v zoI4fqs}0?$#DK=Xm`G=Te?3UpX2(J6CXMwK2d_P!+?iWGdKVW%6i>oUjwsced}qI( z35(4`!TF)Edc(`so+OoDvf=wK6cZE&^GOJZD1$4490w#RdnlXNbv(kHLJ<<_G=dEG^I_y5MP zop|+dC`J$*LTEgql#pIb&Odc`Gz+ghpVjS=+!@^%!Zfd&vU1e^s z*Wda6SDv`=`Lqi;4_UZIFAI79-S6SxL~4&{J@}#BU{527**fI`LQ+aArL|I8MbSDQ z5~+qQcDBd(mNP!aS&^B;Dm+#n3P_OPopY~O6}LZlcbE(zR)(Q;$nm-26Qi! zpFR5u&-|BWj&h&fn!o0$r6xdsrZd3q#wP)MS?rv8&x7}zO#!WZ^jAJV+1e0SAcr&<*4b#M z$Zsd!+Yq^i-#{B7OC!fP?JR9x+PGVrtF7YfvAd^c`(TBhsu=j$k5$c2@KYjpSJeII@|a{z8bgRP_M435w` zNshX{9i>#fp^eeTmTH~5zQ9bNqa$Y`N@-it&MedYS06ZW`dK-3FMyx3Z8Mn2@#$iZq;>=Hp3l7N*^{4 zpKBw!<^6lZcn8?k?PH{q|2T!@$r2OQbfSozRLN0l>N4rMG3DwxX^e@+ zfDn;WBX^Dt())h>3mZpY3*`ucYum@P?$GqwNMWx@ifK@=#eX8zh_3x4krGBaSgQ+K zGMze!JFArBcv@4<_1Nj~UMU6vfdy{3^Uj5Xbk}78gu5(v-F;h#4Yj4Ub6bb!?7rVQ zz%(ZY5p|7%S!OE|Xw1@J(C_7WmT7I2Qbg1Q_0oB?at5YT$t)?Hetp`nt!=>tu<_dF z*;Vn0`zBkP5K5AyYOn$Pa|6OQS)^k%B->%_<*HsO$&P<^Ks+apY1@pe${T8*JM_+X z9Dm{L9cS+NTDQz?d6&6153qSklH@Sq@&k zkE?E?oFsyue&6rXn`R?xd_BhKEVFr*<(XYyTivs^wz9IkytLHs_w&p~lXt3bWDSV3 zSSWKg{#ops>pPUR)E@U;wg2R+8)sI<+QB_sPP#+&y4f*l((74(aGC`wB2q+(6sfA5 zvUXuLi=6Klo??5+3Oh@dsU(>?TQd2@II-xCkG}ue$DTfe9)9^>{PxQ)zQn~S=Ez{$ zTeZz?NdTbLN`eG4Pqx-TjDsmPjfFGoJ*{6F=RSK{k$K;p=VQ;kaOPjU`#<{p_QuIj zP9S)c03dBGX>&=`YfkYG(xkDP3)WXa5^E;#g+vS?xwu&!?#o@SWlLy@9ETN3@FS zlTu0f&iOGPn|&(w?FWaa=10K^|t}5Zb~C|AaFhqHoGJ#sxpR54R5_e5kgO zxhPoI1Wui}$c$Tbs&=BLLny)^z#;t1yWjfkBhQ^q6~$->?CYf2?rNt(m(_D!wN!$& zRvPtG$$`-iW{n2Gz#Kww-h%)@kZOaSPKB9Xb(agyCNfF2#dTDZ=#>Rff-A?vk9_8# zzyH^NJy#FE@O!`h<0qb$;2>$XembSikv0PuYlkOQhgF`WGFnAvpi(5v&WF-D0Pic+ zvM>Sg?Alue*GqamXI6h`00J!RLs@KZoXJUW_pkiY@gs*Nc;HZ5QxQArSY6kZnrTj=PnCIxNCApMF#_PqJvZHXAT`qJV32z zqqS1j*j}FZ`@Ow;_gr=8%C}s5&GOnBAfloy&zA>%=UiEqqw&}|Ule7CoRFm=hV?c- zyTP??zVr!!<|~DOdO%YG9smG%>e$v?RowOQd&WCk5M13rIi-Us4W928O}Jo(Hpfaa zrO0S)t>qK*;T@-ZwVU`JZ^;2`i<{hdCnHN0%;^Dcf zSUq%Tvb`y;gxW=1PaZ~vGDQSaQWQ}?Nfnv8S|SLN(K^d)KhM`zmk%A-mt~e&SR{T= z+96D>HGY6Ir#l@Boco|rU6Y!H0)Rk(^zM&*`1wbFG*=aSuf4h)4aK`USriB*UI7Y% zw4Gu)oVWT;jklzsgH=9^*2)^2Wp-&W*t=(K|GqtkuGs(fx4q@SzI|FL7KuiZ^MP4H zbz`)?{?w5^OBJVmrX5|)QD3xwkqC%B_KEv{^sVoo_SYA3F=bIcv1{UE$wWQiZkC70 z*==sDC?p~RsQRwY^W0k7@Adl2%jv7hn3zYS>&n9V4|RilO$7v`PtQFa>3%_X4{Qb) zMlWo5>n+#KUB+l<8zKjil!yqX`|*6jI{OzJ)imr7kw|OR%d=ZRTQC#c5v^oO<&%syba6aGH}k ztw!S9LT2{9oNSz!&x9WMwO@9Vu>=ni0C>vf7*NgpsSX!}I%^aFAuSWB`pS?o#u(kp zvps98Z-3jhy`EiK%HDe2)yspvwKmIal}bt-xNSm@iHEv=P#Y=jXVLj;PQUB$5C&lm z-c80Y9X@sztuExE$pQ#>NACFW&B9!7{f$#ix*My^gTwiLx#odZnh>oq#+cc^>%5;7 zrE}gnS8;&E;_YH$;*M(ng3M6E&I@W9R3(f;-BU`0Ir!ki?C*T^7as7%q;e5MQ+@{k zAl>bwJ;5X=GyR#sSO>?WQ;wNmeEG;1|Lo7VheM9%BrO$g&%Cq#dR;R0Ot+t0Lz$CU z;FNVytA`~7Ure5!x9dIf{9#{=8*lkp7{*!RbKNZeCY2U3P7K`G+HUc-L6P@%j zOl*QSa9l4PYli_L5(z*|7h;y8s4mM>+rz+-5pqS5A+aZ#KRR1bfvM5Z=x46okY3V) zagt{U!Mox1_V4^>zdNgng22uEIh?fCH%+uPgY$)t3y-u$HX-PJpKO7dhL zJ4^r+ntiWvkfs}d{ckJ;%;9Hlx$fCVJGp|}+uKctRcLD&BbX2%CQ;L=V4=iBgBak% zR$qdGEgTBOpx}5?_~R!}oZNKIm#%c)w;E{96Q)gq?uhaZRHimct1@X7*uH6l+){;w zCd1+ERWaJxt~pTEQm1-vVMsX8bhT$Hb943+V2ZB4(WH3cr6` z#g4wJKOUGNKv4p-IOhQ&_z;-A_n}RjopSF=-C#gwv9QYv=Y&tY8iLl!5CC8hl;B-i z-2DspfBDbp@5W@v_yb-mOm0Z@0F%GBhnp=B)! zwourdLOeI;{diI+r2_M4Qe<}1hcFtAcZTEPXi^jr2?O(N$`p3N51Q)^>OYt;`3f65 zZ-S|+;_nJ`2(H}O-Z_iT7jkiA0ff6Cw}0qHR~8ceqV@g_wWmdDa@fruolTOA_g>}C z66Piuax@wfVlU5}_Zyq1jMf5D6y?s&&i2l5dwXX%8W%-bZ-3E8n7YNfNiUE-d1lvW zdxIxV-Ud-w7?C^ahjH!!0LPaz zb8T-3Gl%N`#te`q0qFl{@7;POOS1E@b&1$JGtW6y)zz1|_snp_A%}*jp=rnlBtSL{ zSb}6)g!RN1K2VVKU_b)w|KT^k$cB7@48npTOSEOeghW%cNRgsBBsIg~T-bBzo}Qj- zciqm(+&f~e<%bm!J9eH^-90@$RSh_!s!rv}%#$Z~?>tno-SgEq3^zaPm=Emn!T#ksbE-*vbx)njOrlarVj;|A{hmMX*SBa zOpB>Xn+aI$f7WFAirl<8?70q~H$!2WOB0neAFh7xmww@Y{|CR^9@$@BNlryac67Ea zQ_(q@^`0-d>=iotblIS(nW)W45DO6Q4>J)0KuY;A&HguK$zp1t{aaYn)yqX&J|-+1 zT64SEwu>u4b$v1(-E7HY70J{7>Tms*fBV1vumApypW|u#=*9^MpTfvFRa?=z=qwx7 zauqccbX+Vb*zMO5(8@)HB?~7aL@8y$$;<$89NaD=h-gY_e>fZt)BbRn<~iq_MZ`nG ze5c-_Bb%A7zOt z(6<2KwR@p%Bg&gq6)-hL#THuojCC18TO!xR7OlrZyA~I&HU&4RhPwE;9{-XwRmq3T ztNyImKe}8|#H&cCVEv7(Xx%PA;}iPwn|{sq9e}xEn?l7$tGj{r{`}XsHTz~Pgg3qO z`r~%=+@hiqN$LBqFLe~Z_;-Kl^I!g&Nw#V_coYsc%3yI9g;qV$NoS63tWVr50y6;a z!!(D$L}Y5&^`a@K?98Y&F}0PQhb=GL0UuV^oTWst?!+oOH%?=D*h(z#Cx@C!PV+0@ zJF%lrVVr>QDGXJu;o!2>1c27l=Lin#O<&-adPBe1JZYh-f{10CZ>0o^D8|6ds+zM* z(>$k?QgRf`ezh+l(b^xSW!O4YTPF+qvBJsr;~f{}NTz0*JIRbQU}nW(t}g0`E#`x6 zS5U&@E&^OQscU!on&X*9^>Qz)@US4abr85j#XT|F-RQ8e!@pJe$ZAGxnTKvyfpyi( z>97C7U;C%O{LcX3@BCMP=l4GQ#~nr759;CX7z!6Zua$iArjN+fA5<_<=;mUTD!%qf z9wFE@dbpi0?blyFN9@|ovigInN}i`fd;EL%A8PB$c_h}N(2?Ow^oI*C+DTWcq-6;g ztA0yV%Nv=9jdH`W4<^ z>$bpPSNYcPulvS-9o(>LTK~WjR4k!l3kp?LP#2<4a;o8=7Amu_Pqc)AbrSky%=O5y z?HX*6E!6pLikfcD7F)S4J8Er4AB%-uV7P)qur;Wxf~)r1Jm&QZ#+<(WMseGD^?Tpb zoJ!?*L25-nFf|JG2-hF{4S0t)-t4K}WrNYS32hEmb)mL;skhwzywx~^LXYJ|J9i<3Yg>du1sizrD5zN`DuJb=o_f%%1qQXt7+8V8s*Ax! zdG_om)@k*(+QVU+&pxp1ZSRlw1gG)D#;JVbNsmwe2cL9Vi`P!v%t|inX1^A9qP~Vi z%i62zGVCl~H9t-B)&6j`-yaUsG|h);p5}Q@$)mztv;baC-!I<%mlZd9eRpgf*c}mq zjUeq-Sq}(RwM2yf;m`f0w&a;+&6BB^8zyN-m`>}XkL5foJQ#ZP_kxJQh2z3M9BJg!NEbgw%gMx>??Q7X~iV&_1u@6zOVT zu~wumKd+`TRUT|Q)bc@4%X>*PGaDj@(H3^EJLVpp9*2eN^cdEoDQ6Y5j|MuJTJLq% z+K}}_H$$GSDZ=9iSKs+_3p@Jo(L(_En}6?be*UGeLYsOY)6ivU2>em}On zV1uHibxXSstEv<`EvJE3>8l|&KB4C?>dCttW>>&dYA37}Q6Tihd^vv?@bxRW&EHy7 zjS6E*h{U`A`;fTw@`$#a`=HQxOnF z5fN3bFDCZudWnRNVxn$gzZMa$=+IRL$&UY)yKS|YbWvG-HC0swfEo^}NitPGAOJE| zKtSZ0D=nIt!ioCC6fo@mYekmjN7@S2VWv>^Xjr$9?ILRl1+-iVX|uN5HL(W1G~sC_c8-vqaZ?OH_G zFa2HU(}#n7%|O4qUgZ>9^r0eBfKW1+Svt5)oPk3CkZ;t9%4T~hl5ZKBRhn=W7A})f zArL#>cJ*+NaWz<5zOGZUT@2VMOnbrUad3Q;DeS^8MI*1Q|M_3|YajUFhyLJmp94u? zCWi-B6Qw43mQ0Am0s58wF@U&oR%vI{f)@=Cu!eXo%IWqQW%0*lyRaZ1cBdaSVOKw~ zZ;FEbQ`=VqP*9aTJ4I|JCJ9Y-e@`W2iQC}O!~0A$oDW68*?wPVFVlbR-Ope#B3*g* zE>mh1v;3&YrP!-0vbzHPISB4fP6*~*)YgIH0*cp8zIukW9SMRVD4Lq)oKHabq{j&e zpY-tTptVwZfa8d;zhdwjBCem)J=qb#X~7m|woPbR_8ZZ+5{WDs$?nEFiaWx;YhuHe zQtU&(qnLAv2(3nhdEPTZHuGJ63lt0iJe9}{DuA>UYPAac)vPRahJ^s^m!xZJbBAz^ ztZWfd|8>E=`m7^nwHKTo2ghxqpr54j<7%oV`Hg#T4BM?qnywzi5J0l3^TVJjOauUu z4n)ku22>5f;~}EZV6QJ0s7bMwF@s(?xl*52FtJYd*wf9+WUYU2;Y@Fcc8>VZ8_w`9 zBVg$AY0Z*T5l@L69=WDtR~IFbnSm+x2Y~=aW`?HdH&hY8fDqKZ#0_*+T-bd$>kzzN5CDK> zZ=|3iX+Az*Pvb{CPC)piN99GA9K=x+xZa_z7Oquh0{ZnI*U=GT7e!jPY~Mfy+JcYE zjh5M3Xwzf->lglY)Mpi8i~6yHLUcGFgg{jSlY(CrCUVPF5MM^SRimNu@r@uO5Y zVU;vb({wP&hX>!=-MM`!(sEWzH6x}OKrMl~k_Z8jI1UsB3b7upm;n&`gRLFYA{@D~ z|H09~rG%#^F|Pp`bipKaEBdt^2QIwuQWR**>F7B^Q_-CN*5CW3Z@l)ZNt!R;xES$a z_9H?wV1gLP03cl<5zLq*o0~_5d$b;a1?A3mx742B8>~z00!2; z5Wx(W{ax{T^H1IHM>PaBA_q$|M5~$qcEF2&M2i9IOLi@~yw9Sd3RIT(G@j%*0pSxL zwTN)>aXh9yeJrU4X90W4#e+YmK#R7%l$QH<*nw;teHQShKejCH-R*@`J;J|h0pX2f zVC2i+VZR4e1OrXoLRn-5EiQ4oYEimmBT^s&A{T-p05Wrk-6~w>VzrUzwiK%> zuytav+q5@|)Rz0|64vFC9zQKk`YoHD28X^I08lXz80=*^001BWNklR*7;0H5E!T4kLwVU}-u47>77+&k4D(hW&pR6J84rTR^xV;gaV& zM##sH`e9HV0y#iN^=*?n-E-G3?+s=lTUZoX2%GY&pxy}@}x3R*)<@=S4^eCKr z>v2Q5p4PhLD!9O6tu5#0lfh>*#f zLX<|cP!`fIb!^}wVE_P7lf&f$093Pa9M8@#h#3IYG{&JwD7#alk(4fh>D(`uprsuY zE_Z4Nh~46Ubi2F9PYLiMftGc3{S%dWkesg`-J7o-Y+~3?Ib|g#HJei&hrooQma>Gv z0Ki1<8d`j55mglsQc`eHX3o?8(f425r!2!bJdft?^C1qyFkshwadk#nWxb)ClzvWn z89voBn@sDOttCQKMO83E7XhfVzEF}s-mdlEGO^Lold_A?-2^gxeMKjk#?4rTK{T!7juJT>0KV4LKJz01pEnUK%$Kju? z_)uMc4`=|S24Jp~8Hmy>zNs$jCZd))2m`}r`OtKX){%S->07cc&$BCr0DusggMqP^ zAJn!@%VaE5u;z!$4xryE9PbO@#%WkjiT3O0GDqNL;Z)m&>@Oe8`v=>=hpS|2hH8k& zfB-2;2xMkijG4Mq02Orcx9pru)ZNVi4u?aYCqy(rGu!QUAr8dMaWEAmw&Tx!EuUIG z>g8K_{2_y*!tn`F&H+ExqZG88#CT+EqLS18(fz!CcxM|Q?vtvP#zz4`?eZ{hhDd~S z%7M9S_kgA*U@FV*vgV>mB&orCn7;k$*8{NvirV>Zdw%OqR=IWOZl&HA#CI#AqZ55; z&T%c!Z(cOch4|sNGvMe(ITJ**u+*ODL?A*ypC(iNrT^j=|G|IrKfQYk&uP5HI04}k z9iRV$um72!xC^c2r!%F!zt3@xg<33#wkAkzQN&?wcDYS6(A(l{$p0%SVkGRJAyaYQ}LuL_jiCBsxAZRO)iw9r+S8EuZT3 zoN*%o8U*N;P=TM2ZhKVQS*Dthi`Z^foUtC=QRJ$}>7+&m|%c=?*%hc z0b;7DDen>qMO^HZN1F9J@f|(Jah?od4l?GOz ze!{o`k*XP>7nv9UF^E~KuNQxVeo?3aW7WhW5r6?Pg64EcqNV;Ys}T~#0Sv-sSDAyF z{zE!qNZJmi(?;L0SMa#EQN#qsAR;d5~2n@;V6!b~6$lv&U~b z9lj6fntWhU@F03CE+iZ`J1_x74}<*IBvA%5FhZ;nBUFOA_i2r}>c@?X`HR2T=KrEv zW=XZMfK@Y6nLq_XlQebAGZK-hiW)JmPL7qbs@oVGXHS<&@N}q0ZgchkP!So5EEY?1 zC}LG1G*AtUzE1+Pea<7rBpQiS$+=%9Vy2vxnM4E;q<*A`WzyOwh6tX4CPX4MaA78j zW~$Ye*iI!AO$Pv&AMOxNloR1gin5)fbdBVTf{Q$t{a|pZRtL`{|F0<(xI2gU&}mp@YksZmy7s@^?rqh zH|+Pj*r#9k8y5PX8WBQG`WXVoVH8slPga@7d0MiCK&x3<97Y=vxLBWbQ`H~x(LP{( z<9c+sqKxYt9c>cYRCEjATXDr&^G9`3z@rKv@_8Y|-S!+2a~5FsI(tIQqD1KHq){P^ zshPPHCeRsQtZ}13SytQp)C!%oa;mbb&L!4`d3|=&l0~pARlHF$ta^=7ht+JdEPjfKZp0z@r8EV=c4G*F)? z?}%Lv0S%BuGZNMl<)%yjG=7xh1cXm|^r4m0Iej$PTX-D(*fH04teq+M0^EqKM@q@# z|2j_a?QnrNF8>`H>bqan&fvRHKEy76#DDgWfBpR*lnrxLSk$D6l?A-kMwVt_jg}c({Yn-q_SuQ2TMPnMKIFf27S3R#1P`{?EH|^d5BVa zQ5jGH5m7UM0O&3Qp53H!F<+H`P)wLQOVRkIcWeP_mY&))&Fm)U?T@6Etb}*$iv@TE6(r;?nEU9K)=&0-+JG8JkH(gML!I%x#t{sL5B-T6`{R>8<8&&2OE#3h5@Vm&AYFG`4n z-q*|!L3A}0?ey~Vy=4>CJo~#``(83s{nODTQ;22D&>4%L#uFPSAbiqek*7m-S^@0z zGS=bYO}yw$t?3#i^qAjRe{cnd%j&<@P4?>1jvMU=(d%K*B9!Z+z!C}8o6ypHWo;GH zz&ItVZkFa9Q;|r`Xvv!{^yVszu7`{LG1jWX$8)7O0N)K$R1vR_dX|;F?D}tp!?rJI zD5zbW3@*heJ!kRuGk5RYeLksd;`rboOc(;17Y+&rCNmQQsy5B&xhh1p1_ z1X~u-*681k3)@lZ8U@RImOF|5blf_z4MCe}bYKV+z zXoNtBS;|R_poCcKT$cSnr|(^D9+AKRvPj)@lnA`;eq@~u|B_%FHGQxO0`Y64hPOJLn>34PLiOHpN^?Hp<33nC0m z3Xny-WmsWHsO@v#>shUV8X6JL6PeAyj#|a3Z{J>R$ z9jLA7-CEvwzq+g~0NJhot9$E1@VM{RGMUGq;mu@VFOPg&45W<~HMI@}Tc_{(J`sV5 zy(86}GXf*HFoM89LD4{U>7lSpLA92m8UH%~(cgzM*Z0Wqw%01FoS zhd{;U)7QH)19g&CdxA!ey1tcYImVo2KPMt0wXDWS=3@HAQAYu&G&wL&k1a(Y)nK+B zjUga-VZIY?gxI*{EK2AAxjO8H^j*i@J_Sqo>&yCje?*J~5D39w1`sL9Fz>>QC7ZTz z2mVs38I{d9M#KQHIXllHQ_e(QLsGonvg(}jz(j;1OuP&lI=FnESAJ)!G1MBV1yx(h+Yig!IVWz z%|yh^M63#$>b}Xtc{P=+8Uc}*iBHS&lOCrTf6{~Ekkh{Sb$Ldj89p`p&{ZSaHw_Ap zZ?DD?EOuFp<2=yg@`TpkT5hcVTa^%3I<%=o7P%yOCjexkm%scy060Ito8>Bk0suh~ zFnIo`BobR)LsvrI(myr!yHRJmigmE~gLyq-Blng$IRZjk-(Jl_w?U|!7&K{YeZF=- zsVlNr)eP8c_n60F@ZT~|`Etw`Ap%$|U8lg*G6De-QwtpcsW=O1LA+uuiw1^8OHxU> z-k7e|EP{J@g1cb)UJP;3@^mvmgpS47)^F9LU6FrvfM2R*z}k@wG30|3e=R zP)V|*WxOknKEk}~OMf2_TBU7PFSWXPTr>e|Y_ywj@CHisxMslWK7RqhHWnZRD0LA? z&Wk1h_{mTG%x8Y@U)&l7RYCwlRj;Tw(xOf%CRkRg1#o@T%P2L3H6(09Yq;n~r&ish z6&n6^HT263$80C`mi*T-7A_gzvczl6{;EHyE}9Wtwgm33<_y?wyYpZ7sh|4US6}|) zt&$p|86%1-P(+bgM2*Pd22njI_K;4&sIzN#Gd8c!^a!P3fBTp{eOM0?tGLr!7|DW# zWlaYFCL98pYSUGAr$wC$Y;3+2n$eUHme*lQx)@l!+az9m4_y-3vjgBCTPH#KEM zWXyuuKTQNP$XNg}GDfC>DPqo!{?5fSl8eHg%*eBQs@{c;6uoZ% z^#(FaCyFWzTnaL+ciLVW68171Ey~Q}kl2o9q)bM)?)On~jrU46O)L1VBjo~)>Q0*C zRb@ngz`h}P_WAb#yaWKB{K-#$`AeVK?nng)S=GcWFl99nL2?U9V6OBWpaRq^m$tUW zrlrMDMYJjsg%U&}Ay=xs74i7HZIVb?Rri=E&Z*l2G*+*}LU$2ma>^IlD^SfTf*B*s zs-jZsMu>AN$E~zxJnxoFyx9FtD8SCh|U2ZyLm8t|=ui$;_&O zX+Tpm@%Mx%qJgPKrKScsi$fq2f&mc{Q_eC(Qni$X8AU9cGNb=!mSrZvED09ZgPQo( zDif-gndJom}+>j_dhQQTbiyGueD|!TmYxwJN@G%L(zI^@~5H3Ap5s4_o z*xrzu8lp=Q4Ghpc{bSH8ABzCN5DBWas=w#5`LFHeS`PtRj(jDaDPpBgX0zG~w3MN> zFsesD?5ho02_76xMCrgIs$eGTy@7Y!Wky5_%>VpXf7^fkFaHn!_~Ncn2y&Q^F^L6c zFz;Cf?lR*kETRHe45*5X$b`9wM6gP1YWH>T&gY$e4b+UhnJj`X#SVa2;z+NSQz+3= zJ6DowAT%oljfN%Z=p6&4hRyB=;Mm|m>(%i|)yw%rRcdq`BbsSoCT8wd|4;n*pMB-! zFTi#?rzsH4Np>-a*}yQ1nL%L8qNte3d@I0ArWOzff@B~D%xq?J%7KWP5YZKzBI>77 zH3JtyuY$+oT!a3arfPu@!BjCDXW1h`gTW65iDo(IuAJh5>C!ly98W|tmKSTi)(3JLq5uu1`&P^8sV z)VrXovgn$A_o>4hZym{FdWx_s7q~$(`WPHs70Oi?74d(jRnG1`1c{kndFftzKX;#b z|Dy-ry$Hiq5ld3A>OQDFWWDykuixeEinQ4qee^#WN4s&{TH+=WeY=FDS zvuQvSv!oEv_XTK%>IIWTk;}UawdPU{h)BH8Lyd_6Ad7dlM-l0^O{Ghdsfnp$ryTPT22Ts83qI}1q_IhkjN&5?HK2jMWk*n!4O3h z00NVU0-}g8lNmCCnj+$y1i=E6Z(In?` z`XT~En5GPoQtl`eFhFA>L=405v5$WIx8O7Hcx^e2cQ*KgAN=Igeh>e@8xLNec4vlt z;V$_9oi9|mr(sifcSl>TF>YxER|229ctQKQDhhl&5;n!h5;64n*MHNQ>bK-z4Sz&R zQ6K^#5mDd}LL4`nM-P_1qYv(73YVK04@n4#uw<~B&2&fl)+4D=*s2uE>B9Q5-XYvt zxm$U?r5eIF4pc=nRkGVAxYk0ibwW_BJQoRN-+0&zJ?JTcp^1p7c=KIXoy5S*fkPN~ z7aw~5`Bz_ky-mem{EL6#D_{TOF2;w46q!Be>79lO+PT4WM|P@#l%UgeLJXWhR4Tp6#BLGGmxY~OnG6EVP7$JxndCPaTES5_FoPikwFhW)>Ju%HZ`R8;W zBX~6IHG86(vPhPc#hYVnwgYnrak#kq{Qvvgf6`wd=eO;0e|5(E#^p3JtExx6vls$o zwJ~x#k^S@b_cn`(Syq$k`$7OoG%$M%7ZDf%0p_gk@Dc)-EsH1<283PYO(5TJMnVD$ zwQ9vrNKwsFtiPQmMYF;86odhxs)vdvPZo(xSw+CR6zYCTB0A4mRS5BHw;_tdW_RcA z^S|~h|MDF#ET{2~$0;IwI>V4ub1jeay*Pm>U=0cZx^l5jDq`4r5jGOml* zj^!c8Dw!iJT!b?>P@*kcQdJ>Nf4R`WEij1y37IJlBf!+ZH7#X#s;Ya@%@CTBv$RC0 z?rOE`V)>?q%++octgZe{0)!m~0st&!1JH1;;fi&_8S5sfel3M@*kulv*#U1DT-y=V z&47qX7LSaHFfbtk5e>umZ+`br`+4|{fANRATb2PtC1sjbZf_$38saSK2AX~>PJT8Q zF#u3>wA0pt%FN5h%X=rn2qpk-RpTm{T_o=Xsb(f{ND`R>m0q+`XH80bJY$03tUh8A z6@x6=+pxHAtJimkD?zGeIA@V8IlDH}LZnCxh#bOhyFEHv|NOuImw)sB{wLE`)#Q+H z2E4t+02m1NNryl#b@4)VA{Xx>5-F$&5)px6#4O503_zxCxUB|(kP*OZ`~g$SV6YpR z7{vfU4@s})9GJF|T?w4j6u{YCR}2O6Pr$EW$ZAs-FiQri#$*VnYB}2waXa$WAvpvR zK}woa&Z4S<2+YXHKp2K$Hx6(bPh*^b@ac?kcX4>|JuC?)1SDqwJuBA1VJn@hI=i9} zSq#ToX>=!->=ZK%6WW6}B?^xPBS*Qfm0HGD_M)Xsa9RDEV$@xX8?8x1%;A-?wet^(y!E4_w7D5)`jLXC?(9uyV#%wob2$&^C~+sy{x{?Sxq$%lEmyNUPq znTQTakO&D0A-EAGlmxTZ(}Rhd(U&R&CPJVRN{W{*5Ms*8gpA0Hj5v#m*&$^BWGWLi zF#1~WWh_)3YgE*KMLT1#gqVt0%jVbAh1U!;nTnXqDd#L%1PKrzFpgW!iQ_Q7aB+4t z55M|Pe{*|oS1I4##77573i}xWDFogG41`n8il~j3B{Z`*;FJ^*P4ytMfj|gk8VItg z0c5k0X-XOx2PO<0h~})5$YIU~I0iB^1~?mNU_!(x3j+{Y^vcC7b5=qykCh3*6``s~ zm_-A?q$+C6s0K`sayFyDm_$WPOj1fYOUi;^$TURWY+_ap!}g;ee(_(Oc+saZPSohr z84uo=H#MWoUVTd|(k;Hs|Gu+W?>hN`ThwMXkqG}d$x{Xb46bHl$I$J$m@y->h| z1guV1%*afELyW_?-SxbvkB9e7;K3NfVb048RIjvEbz6C;#Be=p+T=aZrT6e?7hq7T zs*BM})w@)!XH&pdr^r=|s0HB)>U5=M<#m?bKrO0FBHlU(00LuRMC9#m%ft4^KlWo^ z|Jt{YrsA*uXMg?Qe)jjzx5MR>M2x9a!7~COnp$4mQ@lJ5h@iU4VUtLDz(iPD4|<@C zQ0>ydV;Y#nvS=1dVo4Ni5qxG*(ZYzjlczLS1ca{Y4D6jQhKO?(-+?(zilFnH=afZs*l>(=>ue+%DUQ#+ z?<2qVE5G@+mypwVH^&JGpW3+f%$Vo>(mKhy<+@9M9EEQE0}GlhFmUrlZV$#pfjk*Be&;p4X(oW65cKhGFH#9_JTF;D<6)E0xae!wMN1^2bm%l@?<1}g@BQH z96}t&&Bb${{mj>{AJdoqnAiBwx#3A)jtF8Z zT51D|=bY*^Cp8U>X0RQ39OA`xOJR8KeII`9F43|W>i+nbQ`}-7`y!=KC zHi4$B#k~{J0LCG>br~UrK&V25fzYQSFp*hg8W^d>)^^Amu=Jy1!jUl&ZU^4R5SSj$ z`B1Xlz)XHEjEo!40@kZYRly(xicIaa@og3nq$(}WqOJj8ut)nzvc!?V;Cwf1w!>!F z#m(6#KK$aBzWDN+FB+%uBN`_ld}`zJp>DPr7R|?!$LkSsjf8#vs)l_>XlLEe*EsMR zB6juAk3~USAtChWS6R{8WIb2*WrIK*NXL|AE)OdGE%l_?b_C;_Kgd^%VHIcq6KHX40j$P3TJ@`lz@5xTR2>cvS*hBssadWmPtVXgbU8ETbnS7D6z!l%zzG2HtuY0hZM1c)$a0W|jk$Rh5! z>S3{(dIik+Hgdqo+l$+`!r61b^&9{8ovkFN@xzZ35I)Uuev2ec9kqFkgT|G0U0?X}A=ULoqmI5OFOmKYe# z0)m(gjC1yt7ZCsn2!Oei^*i%P2ngm`J*=lo78SLDON(Pa7H@o23dAdH`%I{qX;FT9 zv{ww|RFjCP&aMr~QhZ-b1G>|gxv0`iCA$xdxo3CE0sxzlhscpF4%_n=KK|WTA3GI4 z_w#?_rI-E)P;YH_sxoKYZHAolE^<=aL~<;59{^%PFy>;u;3yc#+eH{5FrWZ1LC?OI zH}2;wYFl1f9c6dKMhM=sw@hYHeu|o@1wxN~Q!ZgYfK4f9vHg@qbWYjKLSRPQG0dW_ zTbkyqW(ei<@HqakPsBJx-i+aFGtjVo?u8d${>nGs-m-BT@BTOe;nN&fmo#n@sPw6> zBaUACex2k|MbVc z`Pw%DYzXmu7q1Sm(99HCX!*M<%xnRRbrbnTVV5szD$i z#3T}!V);QZvsp9{Y$JKgh+?SimgoRkG-Xi(LL37{rXk>*)U%IQQ%1Axz#{{JjSN$k zL)Jsi;}Co%6%fpeElkyzNJNp532vW{fwy<=+{Vq_-~a6|yvbCY#*ccOfbc1gJI`+C zY2Oi~i(&=3c&_10U*G^s^a3liI>x{?9NHQK-fVOo#f!XTDFkkS&_`zOqfxShOo2Ig zcJNzoRp0>-H&19>=k*dO$D8*Hl7Q1Jf?dD^u$6jUPI;$*!Fd zYUN=G`*Q85B$X5`Vw4vCdLUS8MYITRYJlomm6T;SgfRvn7{Z3PZx#;vcV2vxvL06@P87wkUd7&k_1<(GoaLSr|*Vcemhl zV907(g)>-ZbV_cH;6hX5lActDRR*hms^((IdIEcE2qJ_b^8S$C_sm)35C@3E#qAIM z&YMrg{%Ra{SE_kKB!FXNGZe604EL^PLW|5}q-?Mm*pq)#a*Em_VN%Uvk#Go9 zTmqP4HSEi(01yx#9a7{n6_Jrj3f5*(5dpKn=m8`WOi3q^tak5mQnj<_#_;7NB(p4~ z#&AwTU?w7}%#^bbAt4MQ%yWA2h1*Ot4yd^MlfrXF-z`P-4L}zz^m=Ib7z}KYQF~s&KV4FTOCyE8LT^Qi5>a5!4i1~` z`NIb{X9xSC`2y&Hm<-4@#w?xOy>hPoB0tn6lyQ5~vL1EX7U*N&mMJU`)!3~~pjOZ{ zPxgTs)&s6DRg5w#;w~!LB!W;o36?&J{^8mAZa_vN-fYi4@nfHQ`6g}1(fE)4;(@Z6X3-=P2&Op`S<4rDMZYUB@7~@BD)BgMZ-3#B-WC)1 z@eg0@r~SkIwBs;~jgb{7N#2doOp(y_FH;gkjDgiGGKmz4?=G_Y2{_H`7nvIcv>v>X z%UMH+US(mRrLBB*krjoMWt!4q&O3%N&>?xRdkBnXnzA4Op#_9Vbxtw{nv(z;B4$w} z3`9ieobBz44Fn9d+dcEa|K~S8_jab@G=6mB1cXn2Oow3{58j(*m9gtme+|}dD0Wzp zq;G$ebsyIEv@Wv!y;>XVwLXItX;#BaCL9H;g=84U?YCZgyHoM8k3IY7;r%2+fTayk zUC@0s$EuyF^y4a~^}aTxj=tU5hl=GG%ysk4AGPC{K`RP2z;9B(CXg+NsETHUkVTlV zmiQNYw-9h(WTxFF3g{5Gh$34KT%k!F{X2 zSA4fmv)U_T799gsXCH&QiwQLf_K!7Hji{5QS*1w)5j;Sw#t7g&E0SsqMAeDS4Oy_{ z7cHO>;*|0b(CJF2Z3(;{RG&E?&vzRo-Ho?i{KTLA+E?DzY4N?+jpJotJj`=M6u=>J z63Z#Y$c99wqDla2Iwf&I3xhEjB3#XRI|MfnKrjODf~zBA-2|wZ?UQ6RV9aJobWW0T z@jwt&Ldv2l;*7Te9I_6PBNHR~H9-i$xnjl4%S-cw7(~|rB{L%N_Rs;%k z=hh2<_y=#s51+=987CloPmEi)gX9SsGA%S|s|^6?5N{=!SwIlp3JbNraRh-42W>@! z7VulXJ%+$0kU>ukR*ei-jm)$6-td+SS`XCDL@p<0HvJ0Hz>n3xomTa?Y_h(U=!A zL`E^gDiCD?m-PZb&YD$4%oBluFfvZnHYTfxs;K4?{(`AV76fB3F?B&HxmzwHGaEn_ zaj4mjVKdNSk`F$2F{v_b&z^hn_kR0^+QG+-|KzXy<=0;O@-*jL;~=7H$_xq^O_NwM zFp(J93)}qzATw_i92xIl&6_}3&B=CAi%hxnWt6NoFa^dTFak_TQr499FlSR61MbFf zn6rD`Nu7ZyWk5qhFjWySiv+cIqXoikpbWO%4hAqMWkxa>hd2(Dl78U%TL(>>@%Hxp zpL+GHCymV0A15GuPmHT8-tDrPEOOB6p<$N{g!VY}Kv)<1o8fPbcC{wlzrqsrskR`{ z8u)cQB6O^+EgT@ac#j+iIRuWwFmBJk@%6_lMQofB_UBiT4@8 zMrk^ahov3i;sWZ#=5i!zRcG2*-6h*+HNV$7D^`ZN$RH6wL|T?~$+H5OK`JX?nGi4j z8;3AN9>*A&C~iLX@t^v}D{qkSBR_k48-@@VhwbezeEy9eXdb@w#g~8j$De(0`RLJp ze*V_kA!Q~SBR{x2T#SJkIgqLbLS}Cq0a#$$0@KKNHH#-o=PW}&QJbBGvYjl~du3+B!%pml{XhX$S_|p@dHwT4X zWBK;&O&tYQ&9s_yLNDI&1_xAQ!G#o!aTs^6ee{d@z4Ij53Gjx#y1{*;Q5dxJ-SL4+rjmq#F*wZ5D+3UW>Lw42w4?W z4@st!efL0MqB_@ijsX5a1}=I?a9Lvu@l72q7_Br>0^@=cH78mK;SvygeCbLPF*C5F z7MTnnXW0yq2zT2ECU7`T6FU=)DtGFlM=atiulI}S`|XX6lgJC2X0>EhzqKm4QD-^QVz z#*-K)Abbyv=Ra^~K3sa)(^BtUl^!dd=K_1WLcybY_&yR`w~FY@(Yk5~)uX>XFzZomEQci36&jeGRW9S}`(l1&W6NQ7dhSse4dH=g8DJdI`ukVSM6 zg&LI=%&=-AN~=KC=8@)4#i|VPUh3NMz?Bu1294Dz2HHfV+9Qw|17VB-&^ANFzy@}{ ziNo%Nul?!6cQzIG?uRg31~w76bvDMxYKDwg`{Z@{+f78Ylti)`0E02%ewLJlsmNgl z#w3bhfsl%3q~uORKvNY{W(0M*)pd@#AyidQrGjZz=Y%Dot7D*$kN^UZ#nfQR5|{vx z2nMF@HWJww!tU(s;r=R)!^HBm(HUSfyBN6?l$a8f z7966&rUNa-I)oqqNmLCESp#ztQ?Ma~7#BGlF#*0Hsv_2H9J&4w@S4Y7` ztQt|o(reI5CSr`kxV!zry~mf&zvZ~R8Yw(-H{oB@ zF)uX@)r&`=bPMWuQ1ha|T1LHSVN}&^Gr<(i5WT5f3Csy$7IpY1cfv#juptJDJPyM^ zfbr~=A5Ivb=JU<=YR(w|&o&VZrX**(n5CpVb5=wnf>!e%36toYrNA};r%9*Zz;+`k_vX(|A|M2?*a? z@0areDBwlBivZ6%w_}|h*clC{S@#W2 z;zur+;k&QjfBxCqhiMLh4~LYp3_~!3G-qaFg5=^KE4r1)nAHN)oF!>jYXV?sNHC6M zfMX0!EdZjZvf3D!i2%WnX3;Y zmUL^k)48!Gy zT~ch73oPHRQf1aB{s3-{1>5l8r>SFzCWNT(3g@llT=z_YgH}k7^>y~Zmm+&V2cx;d$_QN z!d^FmOaXV>5y|deT)g!1J0yp%kIT#5^Uurc_Z~fe_s)Jg3?b$u(=0KD!(sMzORAEx zSn)phlq!hGoW#sxAS-jBZV}+U+EbQk&OQ%p8W9lGyE2Bv_>Oo1?jkw(0Ac6Jt(H_v_Xi$Cnf$j5iSBQJjBf`fkRJNG{E(f8eZ zu-}Z)vZz`JVV;v2<|HZSB${(hS;RaHwrS2ubc`G$YiS-?%=2;*BD}nsra7r9s*VT) zA%cNQ&YIO8Tpe!h29Ns*U_0_Q21DFuy-Z>Tv)X0KL!c0t83W=t4yrm118?Iv#DH@4 z+)w<@Z+-b)nTpeR7YF|A&;F-R`#qe-4dc0Iujc)uVjEpWeO>6+#G@;`S~+y~I+a$B z|5$*tx4z}=ep+6Ts!X(&48}N&yE`wxODNdJcKc0Gy>oGvQ_4wG7H=$`QnA4F9ye5X z4OPbCO`r%7i?1ePt0;udhtp$itdpmuOFO!eP4%)V_SvOUuyrk9p9T+$kz6FKKbzve&@UQauOBESvdwZohEUfQ^XLA!DXdIHF`EiU_!(> ztATrJV=JMg+E6#E5&)6=uz;8a@;QXVELe>K)BxRvl#mHiGGg3}1DY|zI7S0ThTFH# z2h5poec_95w|?erjz9O)=V^Z9JKw(l=}*1*%BydHWSvts@OF!b!+e->c3T7ycMWw( z7YDxB3<*FD4oRXXMFB;eTlc9bjsi>=i2Qi7YK%+>gmgL0%*fylHE3vAOwmaPK;|)q z%@BxyIS>zVi??sx8gGIVS=jsx)b9A=Dy8I6}6r z_e5{Cw%q^Lqh&;n?!_7iV$sDQm0p7!Ll}l(JbU+15CC$%7>CRKG~GHsBLXyFM9D%- z9LUQCN}q&=^u9#lQY=wDN{dUU$Az@2{V2IKMq)z5VouG3s@~fVJQyWUik5hhh%hpS zNEE_uH{3oScH{PQFTMLH2mlWrY~KHVef68Kf8t{w5RoBaK|rqk&Xo5AwCmAX&bT$6hm!uSbXh(2pIsu2BsJSB83>n7`=mV z41oxFz>D)UrlkDL7ryw;Q^k)P-~RUek&iqR2l?vPzx!h^zK}(SaR@mXA(?si!C?q$ z5STpvBZ5uj$h246&soi4e+O?$d*1X&r;7nXWI|?SB4&;;#2DkS+1~lU*T3@a&|lX_ z$`|i@fgfHyG^IPYHfqQOChA=eONi#-DT13j2ljSCXoz4-k`HM)#%hZV?jhnY<$DLw z|Bt;l|F$fz>IC=R-|snhc<;rF7ehv7KqiSy4z!Gd3`vrs2ni&D2r>u=D7tE`?q1#f zM|AhKYIi~*HH{&#EdX?{U$=CX;^6iQCb!~8S~*Llu2rSHc2GbmH`?Ae zAoX-sxqu@m!dfe(Fw7#B?OCT3O`8@0T`(CCh=>$1OKa@vK!bwuKr1DrG}d(d@L|Tb zUb*?}U%Oa)@h2mXJlfp-=662!=vN*%b@s^mI-m?!$HJCK4Qn;fL<+T54y@{0YeiM1 zQPHqgN^94nhumm;t$f-iq0-9D^>s)&s&z%KnVoc2CXH2^CQTPw9l6*r4hD5+#adn+ z)~eD(Qdbp_sz&80Hd0Dzfp9ZpV=&V?SE?FiFfyq)qih6q| zeK@;_Pjta6^8$(B4#liY0?D_J(OPR=)x%Sd4zAL%UQAx_TseQ??9SHgrjtjuwi*<> zy*ty|^?c^m`raR|Q>0c1h<=!WZ_AmD98AsYd@nbjB;=0NCBZW*MRD|n156^c0)t8+ zVWpKbNOVmn4y{bs96EgRt6$sM2UWc86^H)uJKt88HV&_VfEIgUr%{^F4VM?0HO6)Z z{IDjMGK#M0B@wxPs(yiYRrB6lAPfyQ-MHG$uxnj5s5M)OX{Z9Ah%CTpSSd{-t&Lbz z^>9GP*2gn3g!A5`($m+OD}?&C*SS5!soD?@IZommHnC>9W>v#x16#bN;s z1G7a0L8=GZ)d#hmaaN>jCj=r0C@h0P6|-=iiC~!lrD<$kD`S`~YlTEUNMM-9nKt}Dgsht~x8bAN00K@UrLGO}cZPXn1X= zI3NTDKt-CcQob^vA|OK7LRu-8(TdDMZlF2)F-hLROQ^}K&uxo{Vb+A`ouJ@G00M$i zYEWyXXrNVHDM73T`oxj78Fxpof8pPM`O*!wuZrA%s(J2nj&?FTeda=?>UuO-9oNF* zc*&qvTA>we+pZ!+LantztP~9f%7p`!B5Rr1174+-QZ%T@6$>E3pi+b|YmI9^?H*J_ zPH93o9@S12qpB8y!C*LAsgACXhojLKz5=K2zrswW-uGFy7qsoO;&1g`K z2fDR(b9YLlT;?zWRGNrTE7gLmtPBPNy*eBK0256bbL7~1CtYKzFMfH6f=>fkGQy{g zoIJ_X?X%#!e`P(S^Wupt0VFZI1#~b=gW1Cu3ZYWo3qc}+N;xK2ubsH>iI$2#8F}do z>-!#hz&1P@4#vZpt(nf+#tkk9XgljF0m+ZKhsc2<6LS7Q2)Q!|5NgLoM1q?TTp-ZZ zqtunwl?Fr<9uHN^SZRIa@amw}gKGGNuU-A%=;g>AKRW!QBDk63K*rDlUa`yZL zg$J5;TibP(5Ni^{zyPEa2R*c{all_y8UdZg06u-`a5x$O zU_~$-P|K(_J?r?!RySQ)zxlJDduadl@UHjY`*)xFPv_6gHdcm8RpU|Jwe5w?>9|%R zJnbw24r?{iG-)jm%?ulB5pXhX1f%S&Xs30sw5qFq_U0f)UX~&MLH)#j;k| zvaGL+t3ib*wbG=ZvsjO-=UjK_(cRtp=*vF$Cx5s9s#wYskR=d4&E)uzEz{0GxR|@Z zS<4woT}VT#?(}whIwbgE{jE&{B z)!}S5+umv13e~Y#;|AZLR@7N;x-dB2CAknuV9&9m4w56xsi|wNeb=~nnHXPjb&@OGuDSqL(^6lOG88hGO7opE5ml6V0EY_7V1I0x;8$xwxX-* zPdA9~x3pZ@!Q+TNUOtc^faP5kiVTQ?j#tcfSnX4ctC6R^};3CQ-e1rZ`L zmMg7@6eA!~XRNO|iOpn15PTsGAP9f~Tpf?A;Xv3bu!mOa-A*d4u0L{Ur=77n^0!|& zbFivd$`#2H2%na6Y~zCMS_g-|*goWZM_w3L^Z5aX86L)j8whihFvQ6`3KCK5AgYvB z)$pN5u0oOcRgvdEPn|jQ&~(?V4r>7#R(fk^x9fO3tQAVznU2M|HeL4+NBHVW35!xF z0+Ys&aupC53RGMMgy+R>wlIrm#Y$0C*QhIGIF^u>d=2wru1J3N-kbmEZ@;>= zxqEoEX09rd3!6K~*2b)qCfS*`hFJk1Kx@SqYb{p_31L`iW;wUpRJA6hTyGs?IgHWJ zg2F78VRdx{5!klF5m^`j$^ZZ$07*naRI*XkXt=R)WL#C#*}3%_Z~4<{pdxFzuCcDF z@p!ea)Xwhg#sJmZlsmgYIkCW8Wf?@m8z7n7T8T5 zW~Ed!YfWcb%Z*`S(OM5`SN`Cr4_Y7wVPmx-W+u&}iu6DY^r7+U2tg~H)a&2>XMgsM zgFfyB^2XP#fBpUkr@Q9lv9;;Uj0bfyoiYRHx~j;utrbQ@Mbx!sHfwg94gjr{!Jw{d zU1>r@-@uQQps+Q=dZe}Lj3H_@s*Xw3)eVO?#;YSMeC(#z{HI_2y@NjPr92T?0^!qM zu0OWZwbRrfJ5DPsHX*XZC=z*K0Kya$^f?ip22wS8@YGXr-OuHXZ@u-KU;6mgPB)n} zD}xFVnidX?^<>%@D~6$}v@yn2K6sO#-E>(50GEYSRT>0Hp)sa4rmEEH%Au8kR+SRQ z@ql1_!xz8w*g+rbCFIqwy8iT||FpByHjTah$ZFGBt*aXO?B=dgm9DC`?GS_%0)Vy9 zw#Kr!f$XYM0H`$8S{rMKsOuV3Fc?(V9eaj`?##LEXWe*mI@^8ri{J8VzxH%930Hvwx%xq@5&bn*B^$T>@g;v_NYqQp< ziq}Sidazb&rAPI2#~eANb$$5v|MY=_KG3B+DOm#H_lP{}S=DUkj5VFG4edguyvYe6 zKr9Fd5D1P1IufXeNGUyd@F__FFD^g&qVWTd-ru%7n|1)OIv)6-C$TjgY9^GA7ZQdJ zJ+4s~0108Wx-!yA)wMD#$Ja*No%!lF=%A16ise1`ocPi=zPmMTcDHAPn(C_7sI?VFA~Ipao>5^xE3m+IVeTp(U73+Z&E=OqzCZ z^oM`{cRzj5N4Au!AWI-^QKc%aa5Sg{0U5Q{ z#_Wn3ed@EzIfCD7vIN5KeYx=&mQ5>c#Sfu{tTsXsDb#}po_;3&70YX1|HJLszb8>d zN^3C2vWOz8DlJwt(wW%=#?Sup7ryu1T(7(9#kl>CH>|E3VIb&?VHN~bfSu(^;n@z? zPrm#UzxBrly{Fe)?!5B{5Ah?`VqK}cb+2LG>3A@#cbd_kf9C!J-pi$2WBFb%{FicZ z`GHsbSe#2y$SDf zzXTvW{sXT*d;W*-pUrI7F}x0JUV)O1>k!h2*)qD?fmwnZCh)M8&Cq^ zH9<)t!rS{8PL*h91F7%D6xg#xi5jUTeB6n*Lw ze|C@uaFyh(A9~m6Gn=-ViS2+b2xtArWxkkF00B^t00~s3s=?a&p-=thZy($dTs8Ue zkACFb<7drm!lo5A=(GW`A$yY0QH}%&NP*I-8V<&*H{W#pH~zPOeNg*<73IzkeRyYc z)3h@-9atk`-PC0X6ACjyKolfI1*A|{x*m@7cX@-nLV)9kKyo1lKRr6^T2M;-6G? zisJ1g60e6^4_A*}f8r1S{l7n$<9QPD+IPRF+1a+;47^q3P7HUYKs-I%izPP`0RS=T z0Z4(Ws2U8$Yu|VCb^rJO@_!uIAuZ+V$r1>k_Hx%-@37YR5TN8XzRWFgbG>Ck5=}nZ z&>^B5w*W{;N@@KUPkBUq_lMtk-y`R3Gez40SPb|VXIJgfb-dSt$EV!-jv@{b0R@$i zrh2%3^yr`c=6~JaBfDaG)6ae6^r=Tovje6@u_%ndp`EORKC}z8G2f6V=m7;#fCNcM zV>PT-)?fC#>woEg{iXdqvMZL`f98YR=g--80;cnZ5eNzg4akBMqc9C~ZJ+=Mk^llK zA%&`@dbF~>@tI%$wf#P@rCe260^!qD-uU)An$A(c0I6U8 zoP&sfl+yaMfACby8@%(~Z{Iq1R=NhopleNzk~bWm>;5t~oFfHKlPW@I0*{C+C`f_| z^kBGl_^*HOllymsmo2yc^iS`cJHzb+xpVkOVY$aRd@*%X0GK~7a+9dg1_%HHil87d zYEZQvt)6)1GymYIjJ$HYURjTA7>8_5j**=?*s@|Q!nE(C&kq$;dN!?nYI z{aa7HIml|x_r!%ywYq4(ugKk>F^ z>l~Pd#5hMN0w4 zAbfhr9dCZUwFZ(eRQi6uKJm$~^3v2@NDH%dKmAwoq0$g`)KKfH`l~EW%v@R3vZ-OtSq+KwO)!9Sk>+Iv) zOwe{H20;Q5488$ORJbr4`$}2hB`#bAbKwK`D2v1-TX7y^RZ~44A3plI|NNW#qlBeA z8Ce41(?D)})9b_<5sM-z>o4>EWw^K471+bSMQkwhfMtv@tbO_5-+~$vY@;N-<%?PKJ)B+$UMd@D1eMgRIP?< z&-}h;fAZh{^0n3j0KEDg?`U=|NH;?^&NGaW7W?v8C>!e*Z{O2NyueSKT^BhbX6%p! zvh>;ttKndE{ck`1@oTMwr94Sl0^w6y?t1I%yUvKU;L^Thwp-@-yPRb%m-!`6%IiD> z!({kFx%_eR3lWearH8fp>>vHjwNV2Az-#Y)W8>YSOehrB{cO3%wAz*7utlp~Zu*xi ze}CPNx=6#Eg0qx8J46OxP@w8+W&KNk{O8wB4*>A0x4kvGL!D=sN)()<#g}(x0L-f( z{u>lfdI*wD;9(#{4Qm{XH%>g`GrxHa`Owe(k01N;w;t{$+hAtE*3se^5saq5JOp0a zV_sY*b63Znu>%R2L?A#ZdOBXa@#bfJ{9iv+l8KfwFY4sU=O6SwEM>9W@#b5*&H$U} z4(;cFWa}ID*19-Q2@_XJuPoPwEQ(YnTlVoJN&zAu>;|_!>v=al^qp%mmGo6_x~to{ zfVL&bQ4n(i6y_<0&T#=77A$$5DHPL)GkxT*gN#oUOmqGtL0H(@uD#*8&wcE>*Q$Bz zEADw?w{srt%%LD*pv9Q$B>cvher>#{q~FNJR30*jCV0NXXkBOQ{n+33@ z47HGHE0#^SwYB?0x7>2y-~au!P{mT7yext6DJplo`Bu|)!WMmYD1f(f=k5Js{l+j~ zKL51*((ka&i2tXJ^0s%P6ncl)upNew( zJ+HII2%Dk=xQu}<_V^U0eeYU_`1*Vp{TvEHf2mtQlM(>JJQhCp##8q_e6>{ZsyE$X zCfmqe5fqFGqJ0xRI!QAfK(;7O1^MRN;(TJ}Rq2|{K_%rT!H3eJ<`Qd_>%PK2##nrFY{ zWv9M*)v)j_AN$Co4+a$EP%+sWkISA9tw@3?zW9x&FD|ceSwa75BWs>~4Z>NvtD+7iGrrHvRC~VHAIH$zV#P83W90Tg-BEVOk#mOCFBse$S+DgBcTtR*|{}mhNd&2 zXEEl9$u6ymnP;=v3zt~<)RU**(CzPSaVQvP2L?JQ(8r(!a2TCAaqXjci9>On7ni*M zxU}T;Xj1l_eZ&ZNLxWRcU~5g+w%sdlf7z2%#cSSjcQ@Su+oi0?Y~{}PWFDRO%$@DO zqJLz2ykjro0})tCgkcm5wzJcnAHMB1mvgWemmhuWJ!Z1)P|%$cgnul~t*JV`x#=zsY6$4)(Jn_X}o(Qtv3 zjT8#}%gm+>-rQwD#U(Nii<#3o54>Wj+hA_>%!1^B5D-SOz*cN)o5{J;kG|>WKKvwA zv6QPTOCWp-$(?V$#dwdX4-LAQ>yuH%Yv1vCU649{#|8|MO2q6-&9g zvIN4XkhGlGwqQkQY3?}@`jiKW7%KwX> zU!Y)LLHYN1rzJa^z|3|Yd+@<`{Nm3(F;(31&UdsP1x?mFEgkX#MwlHSAR2`-IYm<=dA74|$JM3AZfFVy!jZi(mWVC!mTm zr_YILQ?F!{Vn_C>0b2lRS(q@s7t57=e(UmNp^=ce5giF&VI!v9K7anl-u>n)`vQP> z|Er(fJo7l42G}H3WU!lIQ|=bXczX^CMb=2}6v*l&FhP1qC&@KisIu=JEj5_!ihwY( z1>2d~&bPnwM3QOm{=oZYJ6mqXBnU&+I3`bvNklLZwUF`>*`S9#BqCG+0Tn4lL>Mj< zjOJo5dI$+tb2x-IZbC ztM9p!+bOWgM(Cv_Z!amlqLJGc=vZcm%u~zUyLsh;lA=6&}+ z6558vfx5{Zy2pMLOs?lMj~I#>JH(thrT1pGL$20-GF9=#yjO*(XDgmxSfIT9m5Ea4MfWKAQHg{kDd#rzu+Wsx9)Oqe@aE8QBlSS6Y>>Y zFwyH25X=*g7CT4<*orl_o$XvW|Hco0@QPHilxrkQAbd)QwU*;#-6WFT7Lvy&7Mb~^ zm8vQo{;ImJ26bImbzM1NBo)Gk^B{O7C zRdL@#XUuFOwsZZJAa@ZbjLtlxMb=nO>zup9|0$)E(n@LfuhvRwt+ghlNhwk>aEN=t zA(a30ql0m`QW`A+JKIQ1Yi5(jA3J^ddRWS}lV$nD!OJaozmi>OFiU~U^WJjTR~D=A zOBGRy>N{|A_@}jlz`Cm3Jx>lj6$ErS-R^_339Ogp675MSCoJaOhjL=L;aMk7KXh3a z{IQcKxSgRG0!DtxM|Rz5nWik39UCZKlWu!FAG+5T`1C{_J>4FKBV_CGsWnr}(TwZ2&=? zrR0d{9=L?jAhFL%cvu9coqgn6-@c?C0N@QDeDBWr^R}IVA2pn!q*>ZeVH4&D3-QuO zAV{Q0DeZhDTD!|4n1?<tv`Ywt4S=-5lhuwQ1&8>^=DE+5Q4LtVUOIH>idghJo?iSb$nlXFsiV3n3CKdh1;{xnq17G zAX#AD4ftfhTYv1p@+Q$D_euKt$Hswr!iHoi)vbuxU^LgxS+UL=?YBApq~Ow*oT1{L6wn z*ITs_hrzJSqa-!K+}5Q;!b=$hgpFxu7tWr&9k`R?(pqs>2LoHST{oLN^w{~!Q{z&ul`I+ILCP(6|45*Nk}9Gw zQl4U?=Mjx&uDf+vFuKwX|AxcCk&VOG9Y1#L$dQeW!^e&sSwFNk8jT21DG~u=toTMS z87S<%yhAeV%a$4C3$mzYKF9(9;N;CG9(!odgpt?2`Sy0Q3x3L=A1zBc3!GO*<|dt^ zfQ2`Z2%RfTD+&Qp+B4#{@X(45I{9NFh1aimZ&Yab69MQfoWB2J?O2cA_>6Y41GY_t zg8)t&IRPvjq8ZvPB8a&v$i>54P)sQm5HZk{`QLtlhWZcf?I=#$!TFBiB*E{0<;x%V z`kw7(KKS4M>?4nz>t<81E%XNMF7Sp@NeT&*KQttZy2KaGlFLNy+bHV&_E96o&f*wJS`tJvk+Ni&i*+r6*`9D1@?j)j;U&A9T!R1r!j=I$bFs{)WXts?auDx!sa&OghhgXD6T>>}TIx4+rk+NU8D4cu?1~*{o^W&X}fYS=icw686{lg;%!B{e_49h9r1MwIGOR zA33*B6}R4dXET|AH7JP=<{`0?<;;Z%vnR@`F_#!Yo+uCM(Qr5%4wO>PkO*EukOdA< zm|N9~33YSKsnAFq*q4oU^n3^aEvUUBh1Wg%SQq)w-&p9l#u>?&bzSlsUtsmoCyL(B)=y5{Qcc_`RbS zz2+6)`RYF|RK*R?xw)IBWKr~yV*mh6A|dZ7(?HDdL|-NmD`_!;pjJxNbv+smR>q^F zM>b9zKYIO%<2T=Ua%26_a4>KuSKD>gGPC%rBR`uLXrbH^Nnz(+(7n$eL-hqAlDhTI z*Z#xbE=l3R$g+Imz{FZ3%q~1r`p3#koLUL(vh&UV$R#wKVYpbMH@2z!R zk5^W-R+ZLDQOKr<623V)hSHsj*}CajN&die-#4MQ-~aN(R@ZDY6>CB#0k^;=Cu_FA z%SW(-t8SRa&o%M#qkByy%5LuyJ^OP*J{RuK72Yfk1+qA8)1+gH4 zk_u@MzzT)UyreHZ5{ya;Edo+2H7Av>hQr~?%J{nD$8LJY@zGEpS{pv|tq{>K6n6T$?;v`CQ@074wp6(SCY!|`Y||Gipkx9~GF z0Orxbo(Z2eGc@dbM3VzFmJP&+S%kollETKO?1LnCzvFJ(`i>!aSGn@g6B_1A?IrwB zA=8pPL!iTl*I)UguO#v{B=bkP2eXmvCnz#)=bfVE-Q0xmBl^S|)65>16kw!T z{yBAB$HdW?j24xE31X8MqWIpvx4LYAlc^+5Z3JPl)^^=wclU$8cm?H^OSy`&j1eA; z7-NAQ7vyk>V+_rp4@n57keIj*#+Zf0L?m2_!51gecAZknTH7>@iw@@U_?fetTies= zwCy_fd^7-DSmx(ko|$BcA?Y8k3F}q>V0ClFI?`lY5Qn+B1{cWoUCLS6`MucrX&2qKv+( z-94OQ2z#PndO>=1T*Dph+S%RR+TK2U?p)V(*Ij?Yzl!Db>BrBUJ-fBNJ(``k`6oUd-}RFp z{;3BaehfHALHD(J!?W}iy_%Zz2rha}^iYemosr43HD+^b$GB2~&R82ygM42XS5Ov_ zvWr&>$owZ{x)f&9&1QX@;KJ_InhwgoyG}@~poZK7SnIXPx@0&d60$5W14PH~s2quh2S zqq+O1B|Waq_o|A-8Y7h<01~{1+q!zP>Uq41KbBMN9~b*xQ!rGb`sA4Vb!sZ|HQ`xH zhKy@-g<+xS@JM+kzgc4V>L}L(LY(QAMW1(HBizSCo3wnQoF)!)Lru}`bfHt z_=+2}?77>ULH|U5W@u=c{y5Ns)qy|!glJ;HbOMJcATSt*_Tdrj-b>(f?$f#HT5c5o z6iMhfVy&_j`H{F+{wwFM4gLv6G(u@1*^%Xw3(+>Xa_ zQUU+Mgj-!!_M4aUv>$O?yp6gbr5f!~nj?rLBU*dZ5hp#NN}RRq{i*s-@5tH}@BPlA zz-eu%x%)#R#lbch4!)+nbhTip>#qmeDaHUOSBTzb1J{X3%p?}{oXVOQn)K7xR#%xx z2?jQLzi7Cf9BXr?e)~4|5D{HdzVH5fjJY!`pX*9}t1+oyoYc=uo(lyFt?Yi>y8XAW zvF=$Qo%ac&h3Zp%Q#68a$CCd#hM?VSkMYtJ{kG~Po4}iI*pwXwAg4)VU=rx#*=4RRGCEHqM?pZ4r;PkyGk*_2>Q5*y;c zW}QVeTi2&Z)6;@@MwS*7e7tcqmiykER>}HgJAtSuN3XFX6<&67yA;6UdswZ&8*?m% zbwe0Lyh<|Aw0~xjB(fzRj<1R_k+ySK0PD`TnreBMVv0nE#q*rMwu*8p$ca$%ZSdc4 zzSP0c@3*syd)Ik>3>CKsut}Z{*GdbIM;U#@p6-QTps=l9%IqiT4J2<-l%E2>l?Wz1<3z8SGb#|kTb7o?#oDhM~cb2euj^!f1Kz##si+H-UrS4P1(Ayw4Ta! zHI-!!rUX?aO>tX!hyPAw+HDYeRBeZ`t_EqAi4s3jMh}W~rKr=1*YoAN4S*WXD-6#* z?n!>igqL}7%PtwQ;)$Bg+dm)_dmc976bN(g86(XrqdJeVkdN*4Ap`k&`5A_^t+Y6N zfcpBblJ^fS7kKujcz??DfVkot!L)dW8f*SIr-+gBJ~@AGG-Z|^K@db&uEW;)Z9OsI zS4P2ygNCNvB}OpL3JzrmS`PqHwV_eDGU-X_AO#c1gK+3$?^6V)TS&1XkSpnxQLvCC zTI0kS7^Y`HCklnavQd)1D1@4XW#*%A(`v>9%-GxjD7Pq#n`tR^3a)-KA)$7ACi$>v zg)e(P+p4_2Ae)d~P@Qp;X^Y{fNKPzb-z6mNqgpt;9Vz|L>qFdwL6VF@J z432qZ#H>noH+0FJh-+Srr)RLj0(V34VeN8dX6bi8;=ZWJ$9nj#5ThYmeX&7#7FTa< z^|x^lI@tT2QfCMqSlu$!$&Pxf@*~W4A-d~p0D1pfOy)bAp2jO?8+;Pt-b@7h91@~v zZT;J(|Jy#MW}_BX8WE2LCj$zrHcgK^EV4N9&~9M$6nbGHaYgR81tIQ1o!K731EF&= zJb$Qy=3%!MB6v_EbUzNQjjPuDLlLJnUoYO81K~L?+uWfQ-mp$vQE;F$ZO`4ao(r-6 zy64$__+Jb?r)LYf;0J8@Nh9ja3Z`S3ob-6pJ*?I>B7TV+)t-gLW)gTCdIE|Ek6#RCG%d4a%iEAS(0y|fJU zZ7ze3WP1nL1l17V&HZTZ4?^ePbnf8vCt;yTAl*zKC7IWa*qiAi`KF+?*!;^H!S!`9 z(Gya8UbiMgCpbKTT3MYrFa+k)$z?(SC%=iJqsqutbDEl_#HYg3B!paPH71%C4&;(4 zdq)fCfdQ1Q4mX`?Sitw`jh+&$KmxWU9IaGq?~^1;U))6cyr4j<83# z^I4|!7^3LuvoOYPzKqS5=Eo#m$9R5B+&#Y8^mqMq zZ2!_vp5<;8^NI$GxfXfld=i0AWn#}r=z49?*ce^Y2op>Bt^1#LwJ5*$g0oQ9n4O;l73M4>PD28aAxSH#W*~X}02SMdwRFe+L$$?S)A2cces)pKA_) z2qz~qa1gnoNm@?vz`4i$#~!PZDkIL_3@;@-H-W!j|cVv%rui3&ug{vgqbvb z;#*6hT9L@W>dXE1GMy84(4HkF2>2_6*bYRo{J!vJi`tGM`h33v8P{r1~o}OwD_0avd6@{C~yNk-eq7E-cgoGRtkj zFLgFnJ{3EmOZb0;Ez<>vY@In|J3h;aUSMZ7uJNr) zHKHcwp{7MquZyOdN24vpL4I23m@vO_dND$^i7Z!9k|;HTpfMVABoyJ zXvYp5WDSX!HFbA)H#SP;9E!>8E=E4+rIJlUf3eNJgZ>k*hn zflT2p5r-c)Z*1jV2)u-oIqDu=MbWiy1m-)snAqziHOC8|j~_&Suv=wpyE%DoC1f%G zyui$a>6meVPaPHlTG=T48RtE(1*|rrVB?V><374M+{qjM;qI(a(AFf#nEtk0`Ovg^ zW@~hW9F9xe!OZ7Wflux2e^IWfj1%5Dk%~qxB+U~`8!U0Kt-gM!*@9!S)>srY43w_% z)ciI4D17w;MhurT(E595@G~Vo1!96&dz@;UIleemXjodQY-e7x@+M<~Y6;S`616B?cKJB6Kdd3I(KV%~ zcEe2QmG zEGC|awjsa!E-&-NPX2=~y;vs*ZT+`#YNfBRDF{|;2xgp&k{ z3XtCEwl2UA+YJs$+9)`v-**3=q#g~f8V}HX+;8h=7G?wd!16IwYU{_f*p*dw@7mjE zUVIjGK%|ii_H=?-)1!97X1b{cNu&r0=W|u5T==JadliI+*n;!35nNR@^;HgN7^)Gs6il- z0@38S116zU$z!dqWeMZ;Al#G|Q*K2?y$WyhBVnZ;_>~x@Ozx3)w9Dhn2K>0Q}p*-F$Cxq)erp3ay_rdVBO1CguW>j*EV4hCEy|!{Z=ZAMRfygTy5LT>Rw4dU%x#8Ze-5|be|nT zUcK5;DcuX_?@>kvOYzQTRLf^gc?`-n2K>-U_NkES>L0IDna#H+caM}vf zl%6C4m9#vqL&w|n%^gLF+3*l!uJfJ70VNZonEV$ML#_sQ`(J!{OM2!PEYrslwJq<~ z{#?D31?qd6%umwP(t41s&J8?@+~ff$Q*!`k7|gi0ak5o;sUZ_#phMYBQtX@!bhrA79&@k47!f?Lhkbm03L z2PT?2k@Nrogny&wRh{Y=HEgDR@LN4*CM0aloqGwyA}~%(S)iqFc`C>EJ{AT5jAWr7)+FLQ1nu&s+>+#cgU)i1glh`)04m zdj08Ft6vkBFtbx)W@|O$y#Q}iU|P}zu8u*=v?-qgrLJ*cy*@CLA<$7t0h8`;s&<;I zB7MO5(dW6PaJ$Qe&1gUdX(!Z&SlF|IG~be(IfEm+$6BnFd!v5p;c#haf%S&eo%D5H zG+;B@PpayeEICu-T^F|D>W*ly3PljP%&Q@Pg$Xw^f<3_Z)nx*pDtD>48B1-ouqfr_ zUtkvZ_uF*3>m`-Z#>WH9j$0mkDWzG9BfT|{mlnx>|06+k_ch(%#XTps2Q-w(cUzZ1kn;#adU##2xxe`PsKj7&Z6C64^ z|6ozc>#hBMf9PDmHd5)L#Z|aDRqueKR}$_ykzta-)js`juy?eqY@||Dh(W+0DF#Z7 z)fU{~)6V5@Y>u@(6B>YXPNca6E;q8?J&2|A;|@fe_T$G|?ciRpz3E`b7Fh!kIKGZ- zlT&m*H~M8>2i1$Qgs>Y7!ZaGpI;I0OjWgSv@Bjc>;K#Cn%Mz9a?n*I%07W$^*dc#x zkY?^k|KHxMtQxXJf^Y%`i{Bd_?LY5q5&dv=<6dJ!ffhFDQ9OMB+|R4uiE`+C@bT$2 zhT@k!o-SaJ7}hAfKo4B%c+f6vUcgmVZ)j0p9J3IVw@-%`bH4%x;(7mP&?J^9^11+# zKo)#SXIE{r^PSY2J9jc8sBlrbghboaCVBX4%#1N7JKI8Eghr)rvAyTvuO;DE%Dx#B|^od5g4)V)e*e*FCMg6*jTVA@TyUZ zeUBH@)L$$V<~`h+=YY_|#Uj8*!>*k`eh148MEiP*0Ogwk9MwQ6Svy4_oq?E|ITIWF zM!Jlijx@`IWRq2=5ys68xUliih3~_;CP%H=!y4Y@P*5~HNrY~D$*qRS+C%TT5gE%A zOi{LOHVamK)4M0UkNe*ABi|@o%4pNKsY;nF*i8!%1DTc5unBIe_pPAMeS=6p&(lx5c|=T?3BnRN6^XyJ=}qL_MDerP*) zAGs{JLA;upiMIt8K}pM741Az)8*?}Ef#}Wj2PymZexe9?Hyho|EsAJc{Sw0ctGYbQeBIBQucE9jeNMrU z?>UF)#e17XFiPBm7V6~~YW4;nf?549K9ZNNmE}ETd03DNxT_H>{+<46)^%bR-;OUN zc7H&)4-)uJPc@uO^z&8E6FM8RnrmWrUwru6pRa1i@~Pxxgy%|jC$+}&__fL3E=G`I zozcejuiU?x9*7+#tbVzNU>#Zwr9WCrMaH_}6UDV;&xBEspz?Qq;?uxH>+39Ol=Z2D z4XF{$v{)TPHO-Uu@O0~C%+_;&XL~&E;6F{py$AX|lO-AsvaPwC_Oy+vX~>XUe8`n=cXP`bmKEztR+y|sWmi0Hbp!gvEm z^B|aESmQfA<$6q}YOz8-up|u!48X?%FxS!R|5BagNsO9Xm36@8K0poccs*<1wdBm{ z9}|DO{ZK6)L>iT0<}?wEv^rbO-+qMkz3vo3?9qObbzq0sMgJ9QehJgVKCC)FKdih? z?vIV?nCiSE#bJ;}Y|CN7S0Pup5kD*r1QVjIa^I}mJK(itOW&;cK}lBW%Zwy{)_!EB zD*vDOXR7unsfhMnvT$>T{nI^W?9%8Y0JAm0kOVkY__wki_>UxUveS|DGlR@$AZA$I zi2*F0?4S%(5RWziq`_aeVt9PkPo%GV&>$i;e8b(B#!5z3>vafO(L`ed^O~_IaRL@2 z!z0T>^*Df;6)zT`oD3Nq25ch&H>rMgYJ1PYhn?K3Mx(UksC>8=&HpdlxeS^2`+;dR zkQ+`HlJ;qH9xZKfQ}OpdmsT-3{a1uKVc&0^VrU!Q}6 zB65ZBlI=86l$DdkA}3g_8tcLaZe3HZc3Na3~PX*Kr^SP)JsU4klyyi<_hX zy?G8;dR;~IahGqe5*MViv)5sxVxb`T;8&tZ#x}U7{e>7LGAAb3t16>6PC+dNw5-Ef&z;*VleRMp)9Fm zoDd`adG^>j+TX)iWGlZ*a)>Z*9fJI1EO2a06clnu_3>^5;IYXtL;pVQCto-e-T*M8 zML7v~l;H`4E}*A`GGa0;&zJHR!h8X$%&cGlw?Bc`!eOfaJGBj#sq72YTm{{HT;V@e zz+ON=Oz&gAohh8r@L>T16i)BW#=C_^n)g`gfi1ZtTN55dyV-d@LK9Gb*x`GJu#XZM zpKq*Tc%9PJ@DocP1&Hnf`^fw=Y6wzDVrFe-uCH6QW0M^RJz6AF%zK^~99F1dlMsYL zqpG*ni!`!uRUZ@M)B}veix#1}5UAC-{QnJv!O1lTlG_Umujjf-3-rndwvPCM%snOC zTYoDR5I96WTg_Gp8S?NwEmcso$!9CzP$kxQ8NNO7(dr2Vr0a6jsKN%{w2Ym#OyNjiKQG51MWGs)_LbV*#+#9V`LN!9oW-q&1j>iKBNXW8by&)%~s| z_%N!VNHnk-`!a7PjA_kaPvxA`KiZ;w_M0y7d7~i2_+(eJ93TEUTiR|>#lNj(A%;eH zI7W5XJ#7mGhWIGF7pFB#hNTz{>HU8CzhqE+V6!MLj3C^b3_t?e$seKav_^d<3CPgN zZaYpr-KxZbiF_dgaPbn=RFm&4MgdX%n7g5ckNP7lIbyRIHX!h}U+a6pNS$iZvVX$m8a9o$58HM!RyF25bC-RPc2WwiJdiqRf5bf*?0A3B zWh5%IMLVz=BlM_5>OsmPD#|N7jE$N|X``okc!b)bL?^5+n+RYtXF|}>kI{2^X8MDV zAifvQ>0J>zV*(h2gOWQpu3tTIb}<>JqI-3=bxz^W`p;o3YowLph5nw#`@9PPsc1$< zrpnihmk|>gB3DmN=?ro16W}~tUQEkB3uL;^uqv#;0cAtcx3PFi02sU`t@grNXjOV0 z(EF$9$oGprDiUT*8_57d&pqkWr5!8gN!4^eP4bdAE<;|-2wkjA8V&V$)Uec+$8 zPSys*tl-q7*Ano$M#-`l(J&Clq?mW7b|-$0sa;dZ!Sv_y`HZ*0a{{ zlj1tgGe8Ka;Rcltq-moC^1F?bpdEPmjb3fU18xxqq*48w5=`76Lrn}%TC8@tsN|N+0)539Mz&P2A4Dmehd!d z9s+NN#tKf?cF*$_{(N|nf1dIImU`zlBHCv?aZ2iIt3%HYWK2%_Y-jK-V0t;A?lO2O zprC2G=BJ^?&*NuOuV20Xa@1+?YTD!~_wJi(&B;w|`^3m9>WOFj^Xz((JL7226YF(; z;mN;)aS*~dAwjm0*{JmX?;+!CJ(J@fNla!Rwf2)ncShraRKc#IDChT`3jN@S-}5nH zN!dSi0BT&v1k^vmXhdU-IkALt>G^H-A8X`sOX9A8p1j53RLZya%_hmS^I4RQo3W&X zQo_}0sZz&)v*!qQAQ5iiaAszh=y2fS;ysjQ=KhZ4et+rJ3SYS#|IVGw|Pf~%qP*IbrKr#2e)_#aCD18RKI@^vgJz_u>oyzK)I-1$z#>^>99TG z7?gh2Wp*H_)#nCgEceYk|BXoK+hJoJy?O7L+(Mnjp9Y^}X23C={rQ%74iXLZB6U7E zLb4&ePdPs->ntfSs-~3IpK-B}QrfNgDx>VVKwGHl|v~ z%fG1vg88x*tB|G&V^G7{YNFih9J{Nw9g^}jQ+!CBB?&&ietWPz0Y0=Z#P3kL=!=-w zxb-*-X(n}D9PE}55`dgiQ(u$4*o{eITB3m`vr8}P*#1Q2IpZD)a%+-9;Cn>6K=9c% z)qkomP?#huYOn*$UV#-ZYa{@;8CbMQ9o+rm{dj%)?y6+n3C@* zgyzz)A?s1jSq8u|ltJdi?ym}#v2ZcM=3##dqmWkqzQqw=)eS_%=@PBs6X8}_)03i) z6AP<2K$Ow#TostDaA=iQ_;7v0>K~}0Z7_~*Hy!E~1AaJAhht})5nrg)f8+f5-+_td zsp_LScMCRIpv>j<@s5OzRqlip>-G`(-~R$N&944-H&F4svE-)CNW4kglVp;_D8KU` z3BCR=fj}iJyMcukIa&%eKw2YhMIHd=Ib#=x`>hI}yqs{e&<@VC`0$d?#~Ek3?dzg{ zoNohjkG)pF)W@+ak&X&#@_ju!X%@+Y&)^l+oH$;C>`F{()8McY_PJC?G&>4P3PY(@ z@G}j(GRUd&`**pha50m5SM=ugz2)_cU7}Wv)PE;DJ5aT8_5<&5n?t*M-$q?5yK0I@ zf>S~%fl~ERXk>2tk;|jgPb6@8puV`;9MnJxk_Le8^2|-BL#pATG49 z*qUtnKfczt2=FCbz**;&;;jHv>N^BL2!zoMVA8jB{oyer!FpQnRtMYKB~o zc@6pv$|f^;yoAVUiDp5VqS2^GC{M~)0E8%+D68WcCt!Et#~F;z0xP!&H#JLTVD*&7 zEma<0pQyaQFPFdE^PZp1GfFQ#r{OKy$UPQEiOisH+9gfW2xB45 zj+GKjfA~W{);J-BB$eOOx6C2@+a{`68%kMl>Xa=a%!~%^PoX?T@kRk0v66;fVq#dT zBM!6-sT7m))SelMz;%tL*G(pSBGHP&!f$c<01Lz`_&ZqFnvS35u=~ta<|LUbe_~Sa ztqXUi0*@p0uDCLA;Fs-0jUIo8_1$BsUD32Q_~s<;K-Q{svP=C#zx~L z8@^+V_cEk{3Sz(t)O%knQbhsB&G^EY*(OlZ_q4EB{v;9GOJ7xkMwu2ElxT$0XTyG9mWm)A?-h-HxU+dHI{hXVPgolbQWT%7 z0Wlz`a}(Fg;`R*K4u?WkVh8mbq6XbI%ym&(IRKz_Bs57MpqH+Do5j*V&v1tMij6ou zJB0^nveYGHa{O9j!>KSNjjWWwVEc{FKlVKH{HLNQtw70xxJ4Z=}=WtllkuR}4lOLPHW^V5YDk0(`v z(vv>9|F_o88OIV+^YmSmT{+A8$`Wcu2lr{g9&?lV<~!l;r%m}P_k~O4b^rMLdv)2{ zDewvT_+r8dzt(Tn384dC22z8d_R5?h!}l0e)=jS|*@1lfV~X^7UM zps?Ur8(ZZ8N9me)7t2fc^~-d@wYJTeH{QEX?uN?$)z@l)zN750bV>}!Uuv}m=YJiv zsF-7j(x}^%3x%mF?nw8lzcKE=i~DYS1o2vAN9g2m;!HB%04=eLcUBLXA`Ta zG zyY!;^yg16v6)Gzx<9Fw{IHfxwVgz}A6g3dEIt9se5umJHm=t*%RDt*G^nG*UE9JiL zLkJHnfl((XG65f^Aumz{6N!u$HuxrceK{0b>+G0UHC1gBwxE#>7SrD zrAQ_QuyY&qsw+!m-|`?c6F@&3Yp7ZCR2r1L|3@HXj2n%8eAqmYHAy|G_xy)$AW% z-e}xPFoFq~1s0CaqHf5TCr5~J&xAPhJR5H4!L3lVf8C>RV5>hnHu$+^Ia5sicdOa+ z+qt*LZ~S9NzY3(*g#Ma2JlucY3Clzs1bk-#dr&{l5F3FU6ylDn^A-O=A< zx;L{K`wp|$!{yQ27s|&d0#=6?U2H&wshFNFS7l93<$Dr#7Mn?g>?S8g`{QiqR!_JF z{o4uN(j!lff?Jx0oFM>THmYO$4cC-NowBz3U;bB|@J8Ctd#^y_*;gqLDYx;Y`({KO zB3KksRN2w!M*8BDL|xav9TgV&SB1Qm!MDFt%cpsZVG^32VI9$EL14j}qIDP)@i{=r zOT~|QJrttI_JSkzzJ(+#eB7vxU)o$uV6eh8OE3HpM`afZAD3oQe>OAvO1?r}Q!0S< z3dk7dtFSkTPn6c)tscijwW9yZt|Oo2?yr@+M-kIj+3uI4Mtptb*UY8T^C?24TQ~bK zF&E4b)1dD{RK2S4JGb7W%UG-P$KkTK(uIi5U4mzjTaeT8Xx`5O~Q%kX?@Nc-$lCo zW5&kT35Ns54I5K~CtZL17>PqmDs2*!hx#?C_bWx^95^Q;6%_;s&tA$Kv#Ji??*l$4 zv29=(8wJ^!;|;l1I3mlURWlArUZgR$*}5dfwOD<8aRRRe8?df^HblV@3Rrb5`|Sb7YIgN z(*p)$LriTy@iK|ZMcCyC>P^fEPTvVFi|eM(_`MWbGA=`uV?DU0O%xRQu#bOTfl;=ar5BAY(dM{k1S8UI|klH57M8X&3># znex|+Rsqk(55tREJ_u*^?4bo8)LTXbH)H+_oObOwjlbPJYJB)$94^pcM(i&$*zWm) z2YmE5(dJ*;tptRQ61LEinwk{0Ep3GnPh}_;D6s;!j3cpeDrjJW_|RugF5wv>MbdYQ z@!3D*fpjJ3uxBF|pV)MnKSlMTswkPJ6WzpACEcH`xV_mwCuB!!+%A0d3UumeTM=NY zT@u3KDI##`4ym$14NgT>iG+Z|7`5Lq+i9gWeqauh$jBXhgYaNsTu5Q8Ks)$@D!cp$j~i+nj0+2`vY|{q zNc_Z^+SwZU)2`s(4?(L{8rQDkR)T(|)?K;#>zBdu2f8#iM5Oy2=9B7H^LMNUv2p9q z_+FnjvL4Inq zrf$60t_U&meIGK6q=mk>+ffxTYBH3-WiuMA${dW|pfq7A?Qg{*s!6JVL=DQBt5h9w zna&w;^};o2pR*ksJrC>dZ#H6YH(amew0#nZ)ZQf!#~?wrS+o`v^pHLgwPQXY4Xaq= zf81>&DnFAb!T>=+lX1%mWESwxve&hTLd zbjU-w#2~7NMK_9{N@U)4zfAnabT&e7c{%xkAHhUXt%o%_+!*PM=ikk(BSJ?HPw!Ug`b6+&PXDZD~?2ygNd$T~O@ z!r1q6b)^WG&)hjkvT4x=rb(t(TSOW98b{HL4h#L~wkk*&euV>xFB<>Vc&_4jSzYAM`$bZVg_IfI25cqk>CrG}#h|lGVFUG7?R^=NvPnRwRO>$5Ky1;s ze=Wg7b4$HJRxJ4}oa1C}puL>yxptYu0Y$qd!%O?lS34I^@it!0>R(!}bVM$f{*hFY zYf^pnGsJ(H$mO>g`OZy}aHkVMHT`VR>*z&bZJ`NRt2oY(r7896!Ba}fs90fwm{O5X zf^mfnuTsDg8Z22hQXrSu^t5N@#3$pDOrcwCQjMaf_;qj&c)^$UL2` zS1WaTg!H!tXBn6{`}Ys`cK@9fX?PC3xAL3sIN$wE`+OkfX? zAOsVQaUNRjlpIrM8lX?6FDhVEG|4~Ii5=i7f**BarZG3nxYbkx!Bu5KLXl3vb@$LWsq5(m7@r7dwW z1FLE3cG5J4i?FsV=FQ3`N;uNBJn)Yaz}GRno@ z_s_$^z4-OWNu z2-4@z=NZSK3F?=AB>s@&PSTEbbDI7+iheXUzkU1b$@sOP^S=tT7(rG=I2NU=7`gOt zCAB$(tZ5oo1C{g6RrqK!I~`pIWmb0b^XP9RDMo9-;?wFbU(1sSuUXHnij1PhVhUj@ z9TiGC2DC^!B7MSwLGtq@%Kxsp+oU;XXU0PDZ`M^bC_-9xuOC8JBOJ3 zGuVp|{SS0FiWu1^YLe*!5qc4()P3~003yorNKGa?vQ`1vlWS#YuGY^QJHhsYD}^`v zwM#4S6AIFX8f99gP6Ys}4!*ND(TX^3;VI87nEGX{km-t`A~*_z-gT*njHy_N+>D^A zyUz6FPaJB%Xf1PRGl&oF)vw9i(wF6KwS@OVJ(Wp-o5WuybixjTVE~5pQ zu~u`CNxN35Y3048`{rAX_aH#su~AB~b~ResW$SJE^x8>#q>wXFU&4g(0*e3VyU5C^hMoD zzJN>=cG!CHW>_b;Hp$yu7>$I1%89FNS^j~a3_yKnm-ZkGDZ)SK0>QIFpM%9UXe-VY zkvwmPc|#$lteG_ek=a_nupJBd4 zQ}0VlI(GwqDZcZMtB3?|?r}Mq`aC4kC`Sx*%5OmOo17?kHX)=r;BK5RefjsE7-&Occ(a~a<2>aaUu6c&E`D64F_{iH`jD<-4W zT)TXJC~&|0mD@@52bCgOeZhRSkNj9&3+hU$(8ejELPas>^?3s$Pu-U`GF8-FLEx*?a2#?%+@Z!E@IZHafV7 z&-CYiz{MV1oGO=Jg`s}r>g;Ab&O`bpcKoLOj&?r-yTo(;T?s05$Llsnv6}Q8nkD3} zf72bRG10>2ku01A&OWI9PjRNl2)up1|A7Jyw@B(^pMwdjxdZ`zxsas>}9a-VDd2hZd z70|NY8U!0(M+y7m5g)srMp2VHYPrMh9ql?ATc4F#eOy21nUq#)P?@ z9r(@iwQ_2Pt-ZdzJr4dVtkWFD;_@P>Z#b}l2`IryOPx#M>@n+a2Lji?kXX%lONv*s zL)@>U1`@IMuw4nEhr$GNx2z-XBBm?qVu0{!QH$xN!d3c+pO`s-L%>^CUY`N3rnS z#;Yme?h>GmN#_t$3x*Nw?Y^Cg0Hd$zLy5wM`xsR*ii!r^&Y!!YiF^jIRa!%*$3h@7 zy9mb0dLW|{2_E)!EnFzB!B0#TV|-bBE>I8KjR4gYEmzy%rH)H5HFf*AxL@vn?D+ib z^lNR{!${z3Sh|Sd*QZLQkAvdg2i>)i&zk+2Od_@zi?6MS$e?8_@qGPH zXax3Cy3DhS`jvg0joETlwycMmCYI!DR+IN8z4Uq&@@Wp&PFUPjl)PvhL!*$>Zs7A3 zM(Tp52hGqN>`SVo)yyJ=x1aS~0}Y=%@)gzry@ZERjK_g`BW;Z}F~jt&l38N3cnd1W z-B($dp>Da;lIJfv9Tv5IX6q>S1uSPSgV`k}{nVaj27+V3DuVo7U=tQhB?;31GK*b{ z82_G7{|gwk`D8Z?we75{pA5BRFZr&AK%<3z8-Z~V`rTQtdup?=JQ|*JSk+7kal;S7 zd22#7e=jl=?%xT@^FA1r#rz4dVeSg46zDnefzOaDB zULf|iQZi8uoQ|NzCV`WVO%>ueKQ5yESPR@Ho`Y?{Z4`c=pl~mKWyxsd>~1vj>q}kFkNQL#cebuSj>gCN zLwwumGK`z4F1CW~l?}2Yh4g)2@AHEr?}YN|N*1fB=?F9F^G92Go~Cx~%Rz33qw5p0~pt{Y42WsMwNW^ z$k>Vb_lPLyy}yD-)JrF6aPig>GmhOAE*HI0GAA)MWRT!->Q^B*O((0HpYsA_EY5A+ z&cQ!FAJ_bsFB{~j@}NIRQk=fc<+3P+(?7*qNm&d-YBqk$;7+K(NBpep_A`9}LaI(K zbpWuN^M}6dTYQ$%FD&fmfyrMB9U6g{Jv5DuBC3dFJPt0Br;nl67(zw5uC6UrjQ!a1 zdvm$?_A%A<+1m)w^52%fH+SWJ{n~f2^Lb4R2+_2lV^^K0r?Y=?Oq7`6!QM2;~^fP~`%gJ)Ykqi{OE(8mnwq5!{&wK2)R zbK7Vl0I4nx#XV&EC6%8_vOjAL$h&>~JAGn$rD1ONzhZ3G(nD0hXL`$~T*^yo>kriR z{bf=bHs_Y^AEeO1mp8S-j{xGpiy z?=VYartN?#1VGQJY>O)a3^8zz4`s`tGW*o?YuhQGdF@5pdTZd{)4aDm*TX6-a-T4< ze(yt6ms(jM;iJWu|Bt3?jE?jBx)V=q+idJKwv&d9Z99$4#zw=2jT+l(Y}>Xm@BIF2 zz4Lw6x;W>#`<}D!-s67?RnKyO*edFsbZiTYR{l`fZ?S|)=O8CAt{-{N9}Nv2)bwpw0m&Z{wtU%5bl%}sRr zS5SfUWTa=8E96LcdagLt(fef|df?qR{EFQ-xZ@6BPjPwd!8~CQFa!1%naUD1n-+8# z8bco$#ucn+PP4wf_Y6PFDt~~P31#OZ{dps^9H5CJF;^gaK6Dx^r9wgAa6EE&n9}dE zM;*{4)oVKi#$7*Gzp(VYOlHcACaa)*4~KQu4l5z2AW~$HZW1P8ny#k%ym;Fkna$r| zLnzUnUajZ?{Vgz0Ws=!W8(X0W)I>l)?atVcG zl!B=~pTvKxhjofH|2(B2mdRAVlK&{K&X_@?=fJ45A1^NdnOHPza6cU2A=`PUJm%2d zxgoIBdEP{*oC|Im$K^Xz0&y0wn%w>oeQ06c){il+m zy>L-Qe7u_7*uiC5*c$y3q2NQhoIIL1ROC2>E;te+A7fragH0D|h@cQbJDy~%LdERv zQMmKWHGKoy*5|RQ8r`7CJ^74^{a5{RpQh{ zO^okoy?+(#!5vO1=y6(((~M&CC6_sTY1yzwk($-Q}#$T7EB!hYT#6ukyizD<*q z3?{oDtOe0+lOc4JWpZD|^TZ^~hKATxcM~y;fpQW^f%$3W?BnApO^|jOXVJ0dWJ+pc8ER@LYcL>UPnto8?SX=_WL5?z-xWiht@rHp!mws1X8_l4YPFK6K$^ zMC+aCf)mocq{bifqYlqss>q^f8z^y{K~~N2MLg4sKjpTz znKL@#5+yqqRf;fL#BYnjpPk*U7}eTq_08@QUR7%k!&6UxKkFR7NJqeY6r~))wuo?g zsuC_iX!&=zmc=rl2^4C9>?Im7G&xIC(h3IG1d!ZNP_6t@=~WRLQ`hoMkhs zZEF43dDl^>oBzk>?dlU)9<#gS?blgTbCo3I>e@z(ID$B^U7l1Txfrp)6@sH$K$0|+ z?IeNvm%Pl@INQCd28>0tzNd5cb}(8YuCoxUnnLH$u`(b8h^g^26K_xAPb2elwqu6_ z{-e_7J@|R(?!OXI3P_Byft7Cv%k_p`opnS zR0e6|?V4vlUo16`RBJA>{{C-;Hw!mck*tMmNcxDS(@fEcAJs)9F4TTA2C&$*-QHiT z0W*={6=Y&_TnmP3s}%GXnld+@9!h_9C@=l;`i48Ua)bFfU*1_Y0guL&hFev`q${q# zrjZ%QS`WddXrV0bx3|x5PD}Hc#JMgXzn|FmL9{x;G42l#!wOyf+h~WZOTk`J@%&np zZRXVEcW3DLc%SMq=!eP-x&(72o->D!e26(59h7Lp+sMo&icNGg-Np;StQjmR2x!)D zi9%hKU9?K70m=^tG8^q-<~KYBO0ly}^61?SXuP+3bX5`BpH(&-RTaxps|w@tzXD8_ zCWJkkUtax`+4Oc-)gNrUHgjN{t;hU?&p>%vxRpGwEC zKk71L(q~9~y{_Js{LamMUeBvlZMaM3qO1kF?F2(s{{hOhdX|Mm%`#%i`_-3-f+ZY7 z^E+cQMp$*k)6mf*8o2fFUC5dE9Wy1lG@R$Y27R zE9##oM(hfUe;bM1B|;*N?HHs6>U|K8em5~Ch7i;+Qo!+MFD_=4G+`6Qv*s$55-Q@p zyWPQ%w%bEa|plnGNh@Sjd`{4lKcCqfPEgunR(*s%(g;;u24u`j&cx1 z=JZ3#naX$`XCzES<+zmx0nL3cFhRtU%O}WY)sE|7Xwhut1?-RPq<7Ox+I0Xn*MO|l zw2LR+$e6+{on&T^Qvd!#Rh8lo8cwb>h0$d6$*CTh7*)eiBn|OO3K0&FV)9L*B$SRA zOZqt)mEF2x)Gb(o&fljf%ZIu!JB}E8ui4S-Vc7p|E@C%YV6*n)rRHk~TV1S%+D&V& z;8s{wlsoyjz|=r;bV-`0PK}H_t^_n%nmim}TwQ}E$*==gDst8e0qrPyJiYoa&7(E6 zD!d7>qpzX-tc2olHJ|G^C38pDf&XUt@-ol&M=pxr!Y8ZEIF1oC#I9|xxp}yQUB=@cgm&$DVA0EWAt-efAN?;^X zJ%EgYgO5}UjZ|zZ`R5YeQLB!e)iN5PhzM{Ea}AbD(eHja5i^?u^7R7bF%p91|4w-Y z+Ef0t-RgV%<3Y?RmB%aC{W*XmzO36Y#;l$u+R(KA%4+CQj%d)MqbWkoIj-uv-kN}I zGxsN+ZULvBttx%u=l6~I!syd@JN2=^riyBTChUQglL^wd4NGd`+NMf7TQXmzRYZr= zbr%#EB8$Nc2t-loD#s$BzM0Z4|48vWQ8~gPZB|!EA zcd>r-&kP`$;PX&kE0p>z_F_?YlIe(_Ez}C%%+k@@#RmsXw10E-y7Db+kz}@@P zHV+gER)vZ$dwoJ`tCglC%M5u|2^rbY@>sEGBSU!HB`fd$I+v`Pjs}}^1pIzj<1upE zA0a~m=G{}_zL?XyY5<&=2mEbtsp8~n!+(;i9Pmy+$V!L=BFU+k_TmY(`32Lv3E3&0 zO|5@$TFC30w_ivewTA_t7B~60=6)9yF*jv$pWI_zgHDsDCHI<yc`uhDpw2D+Hjsv&xAIBz#F#cAKj zaVB0_z=`P@{oRxXxNYRR>EM(2{W3RkTjLc%)_dY=$H|JwP&NkVloK5eOj8+rWVNtR z^Lq%gWxQ`q=-l&(_kX>7Yg^PETFsj5{ZrB@xyCO_WxC9lw{HQ|;EW6>i?Wf3j9kQ% zxx);`wXDijvYcyc!qzoK+hGw3kfl6C-PrsLFY*ky2->*Yn5l{~rZEZGxo>T4#ICp2 zm4=ont01>p3L`U#R1ZQTCu8H*I0)uZuwQ}&&dK`uz6}(Yyv%NR-5$Rj+*S+w(cE!X zcXi&qDQ`Xb-6*WyNZ#gx6DbmXgaLrLga&amHzsry z;TUX$wpo;hpZ{EwUOtAF6h7aUNbZ%WkL^s*;jt24XD|a3bfDO1l{B~_$qJW@6a{lR z74=`H?d=^FfdThCQ)XV%jYf_iaKl}n%SA_%7e7e3X)wi0{?4F(V6ljleC?1}U5v3g zBVu!Kup`h_wh_qHMr*lzeyqOheuJBGN*dZ(&E9(Stl^2@_;`>$yyFYTtH?mAzyR0j z*^xpi%E%~Ab0iLO&6gN#G*+rshV1yWHHON8+fm4_)gkd)4>@jwtB+v(0P85kK-Uohitbzb{i108^P z&x^V!9w$L3mL8tC)n~y^1eO<%UkeQcgEE(w+g8^z-cP4M;F<3?>eGX>d5hcU?QN4; zRATr3`g4;6Sz}8%Gs;u=K1{469_%kC_(!dU>9L>mb*A3ZQ+&zhIv+xvHOO$r1YU(Z z+3GY`ToT%hj7C@4Vov#e*ifipu7${BSo(6E&u6n)9+)d9@^ia%`3hDu4EHZ)U8ttou*8N=RFhzS-mW^y8pr|MRpd!<5 zTzY$~nH)4{G_#!j%N$rtsxVMu+Nm5C+$?|lfpMUK_2gcvQnu<5# z{H2yASMSqr%6XfK4&}S5FniH?1Cnp%4pe0vOhGI3&Lzo^R(jB*`Q;_q*?I5E-7a`X z_ed9Us9WBj_nFgQ$avA>6Ph4_tMR$~BiJFBx7yO`B9fZyRyG2e8@_Wlp!;s2bhI0| z%MRDNcE*iwAyDwDgCrtOzVTG@PLYELNgl9Zc^nZWJ?8}lZXV$qN62M=h=ku2t(R>@-Je(fCk%NfgBMVs_fk^d zp1t}2V8X&Jp!AUfIu5k>LLm#_KfJWlf^ny(zh_fmaNiNFe40% zoG!nIi)>kn-r4_QWc<9|nt{cYaACN*eRKz}e=$WMBwfLtMi$b_>kp)#{R{j{F)KcwE7Ez-hspkY za9hE!^Au#8>Et~-bN@b^jhX;**jqVYr7xOc^s-0K2OekxE(|}fwC+-t9?$KOL#L?U z3ZA;FT$6MU;ebT9`nb9Lz*>rWZk;>zn1vcZAUVIfI&>Is^3ps`z|+!YTd<{%s?QkQ zrl4>DiZ3B~0s`<{>)oGuFU&qNX$;`)Bvzol6p(_2T>x2GUU4#%_x?IuJ^7u~%JF^X zsZqePx4Dc&qihQ;_8L_yWY162Auar?=t&R}QM&410DXds-tax&`k1oi z_5I%kfx~0iXA7r84PFwf>?7@Qd%BeKi}2N03`z{>+DVvbXdI7>0VAnyaq}U&JAg~c z-_FtNi1_b1)D1LyKADNIYn>JnouF$za^q|-yt#h^+`v8>{k94gw#ys?f8x_GJMt0}u4a^r64d0iA4Z4aH&rfkqshW9F&D- ztqE+;_r0g{96n4a(P&2fETvdUKY?uAQ|{J%EVWegM0ZhNA;$ zv_`*EYW(W0j#NKK0NEibiyJKS@}Y3}wYoJv*4WE8@MlLIWW-)>FWEWD41DIdV!Dxk z*h_>w>%M!A@0FDi5RUIX@g6<`+v#;gk<)6wHOZYC7+bX6zPb$aYUMn^g(WzmqzohJ z3Y1&uvUK|2A_@mssot(K&w%U4RcmVj`(HMxzbTlsoA0lo1`UG4W7bTQ!-yIuF72!K z_qT8rGT371k%5wmasBQWIIUG|#~)LuZ7(RH4xl#SPqpw+W&6s5*_$jLGIA^>nf?S0 z90p*5i+R>csnDa3)+AJC=cnM+{oNfJ|7;)`bYL0SPij9QwW^1Ks2b^z9{?jwJ%>$; z1WJvJWK)yFxiH&%9u0;*fE2rhO<60_Xqy(*Ek?II z4%B&t`9_lBx3?PR%ncm94SfBXoRE>lX@d)Stfen$qpK%gWgD z>m@~tPGv5IxicNft9#ClwzQs~_4>&auwXT)y~3Top8ZU(EQ(aY^5Z0iwB_iN@hJMr z?`Un^1nxH_wnRP~LR^R#(~`i~<>vLx$T6F_~aK_$Kkf0l2a15M;I*7e$@5QSkrZd zm`;kg^`Ly^yWKlnyg_{;L#+u7ALQgdGsQKB4tu_Zjr3Lo@$yF+SQYkN)r2DR{eoCQ zVAb2W!9_Rj{(3pZ7`JnsZ^js>?as$Nuj?4F6JqFhecQJCaOG9s5TgeVrK7)LgxwbH z-XX00b(=`4*Yqa;J*@VYDaCMtY`Nc9DLZ`dug`&}-b- z7E}Lj4iR2orjQiL6#~LYkIP)bP6JXr3m`m1dbm9J92q8cd!wqxYr%ZD@4wk@aFjM? zqvmqRG8=XC+>ZX))wxOz`3nPf;4?B+KgSquMo4ou78Od{&ha_1HGFEE^1r-oGqFz} z1ZVS?Ro%^p4~&BX4v>$G-p2v%++ZP@X<5_@z*<0;( z!B|9CO~7#W@7$tSnV$vZRqjFV6@Uu=??e}HL*6qVJKK0{TETs)bj2@(QtrR8aKi^@ zJ8v7)krB7vX7YURcfcDfegjR819OsJ+tMu+j@EiD4T54^31-KSE4pJ=Bxs5Je=Yz% zPh}Tfr~2}=YiVI`yRM-(U){C6=jXs?=G^KR=D6UZcUB|^1~L#C(!fkE+q&yp-`!mq(Z~bhUIv)Sywd8ajtc z#Oy-QEz>rm#6qJYl)!FI2r+dW=sNfvcSZc_WW+#-mQKKXownlA{azsDKC!#?S#%}- zdk6G_jwQPDygp3l1rbjbF+gV2b#CzS)b;UeN>~@^xo7HgzaLc+%MH3t4Gk?wbFbSk zeK28^>C~ihrAO7pZM*@$G~y{@iW06$a}*6rM4j3z;H;7v6=(CN0QK@0A8{KD4Hgry zaCwgq>B>1Mns=x>f(fr^ae?3&TKm3V_1``~#w-R+KshBGOETz~yjckL7K{KcP7`X)s? z5gquZMh7tJkdMe&X(J0156G(AN|^F^*52NZCX|A>rK4P|N05A6y?!!yi)QiP`DJ+? zf%-8XAMim~Y7&K|K?fUbp6cc_>I9GUeGB3qbsQ6^MSIp%j_KS}9Ij|vs2l4`=J&QfX|=c^_C9)Gh}cjP z-&&le86h>Wulg&yj@qwYD!aY8!JVE1F8*^U?KPwSGL`~COsd!HjUtiV0l!Mi95ync z_L)%lXKkG!Q@Fe1@7=oF!nYWEU@KY5CxR7l(|z*egQxovzkOHnsik@E>y2P{r< znHynesMcKspbafr>G0J_L*TjnUolynUeHH2y15diJcWppKVQK1=*EAee?H}zdKqMf zPFFXT+DQJ`O6BsQPF~SU&>AJjCm8#tb)!49!;007hY)!YUjWK{XDouQ4)k&!ds&(L z4{8aS3cn8sgRaYIl_ETgN?7}w-dZ%Bek|(4&KKxOa1pPh2LZK>zc+KY{@z_&+V^#i=L8HSd}NoqDN~T z2T70E>(WMRrPL1Pz47uFc|2seeodmzMohAJcrB6WL)%E`S1LSZq4UcKq5U@)$Ge* zCpuTHoeD$AUfcDc-Mwe=&!^BK`WNwGBz1Y7^KAPO@z;x>w70@uHLbN%7e>Otre+*e35Fb?1L+!InMIjb&P_P84z=}=h^B6-QS+P8vj4nGJER=7MZ-jXc2t_ zWdF9<)}cvm6lD8>tUNGomw}AQG5jXDb;Bq-t6B_!E0KUmr2O{}pt_KN6Z&f1cJnz` zc?>)LifORX+ikr|WUr9L(BC;_oXCH4IgHn!{1xrE?=b~@#3A!(F$uLCtZ*FpKTH3D z#o2tB3GjU#t>68zQoB<@=j8OBB+17p$R^<>nfM2~-~T&Hj|-M^-#_BsKe`_w6Zqxl~EZ zF`0rVsM6U*D1+UWL?0dV&~I`bZfVkU64Z|h8kln#T&+$3-`KA&z6jsLqNBq**NVQI zR4|(9A_EJwN8fxnx7OHD8pbuu|F8`anA)3zA3%fq%SarUY&eqr8mA+oHO)3~LW%b! zSnBG*&{w`*7lhp(-}G;~n%f7zA}26XX*?~_u)G8UjNCh?P!X9r_K{8?){;}xNvUP9 z_f~N`bSJ@9OD&;VGLPGtg3YmhF0DqfwHRhtW=rHYXUcX&_>WPO3xmY};KX}dQPU%~ znx_=^4nFgL&Nww>MVsxecDh<#J#W7;&!CdN9>?eL`)zt60#P{k`yf&xQ{wGY(#9d2 z;e)hOCfOV?5jpHKR#a9QT_)p7Dt0o|IC5TXa_{rYYDd@yQe;)GeA{_lU(c1_#|aQo zx4;14`7lHV=-uTz#UB)se&{l1xS1)LV2Pwl=v-5g{bQChxx_lFt-P|L`VSX)QC=lf zT4@Y0wy6kBA*;Wp*Rgsng~`AEyz&RF9k%-r=#66cImdY!es#GXOE+XlFzTpdkx5ea z_HBDTrU-1=!iFT^Y&r0K`g!%^POTFQ(90oYl*$ zWSOuQUbNyP>B&DPcS3Sw5qY`@1iy#PqcH*ND;qS9`WFUuH$d!7RN13gL=V4 zIrWa`YTa@01}P!Mj^*tgq_(-vIZ%W>7 zYdIrD&g8$wW4_EWh7bp{}QM|t~GvcV91m}E@)wZTFDYy8l$N3t*z7wrWK|di;Fuf|%slLFL zkK4|#+fw1@dSSM$4a}v--=cx3yWVvIbY3Dbg51*XeqPcGp$Bq2M(Q0+8_eVH3v2UjYsKY3g{bf=Bma@rWh9F8Ym*<4*; z&X_21&rM+6JTbR%`@PBLfAN9G>nqvF+u(-ae8h;+ap&SJ-0=qG*)RqJou{JWN>ctc zVP@v|`0g}_0?WG7UwDdW&KSzDOPdW_L*#Hz*YLxJK zoqKhL6GMbAkN>U*2zPpKvGXL9?DzY{x;Uh85~CXB4IP2&+bS>8|EW0MjubYI!x!Li zG%R!v#&dh^xmT-n`~kK7TJ`n)m_-zH$h4bBqL`l=3wHb~>pAugcH<>;7T3VZydoob67KS+~x{LrrS+P!wy-^=w|n;5MRYf-lYtbFFyx^;s^hmH?#G*0xMurfaRJaetP?I+~ z8dc9tT|H+D2SBs`fh~=)ce;C<{<-7$ULSBDzg1@ZbXKL~L*|L+?&jb#%R^CeFB2!Y9xi#0CO}D>=_R>H_Z<@2Pk-9~uGM)p zT@^XX6_>aJ@Vc03YP6U7RbK@0PpER|4mI1?F1WO^Yr+6joFN*_zqW0&6uOsDFS>Y_6p%s%FlwFFX%RoB_B z#$y4~k6^w_7qARC%#yeDLk%el^Cc zCMG2&1v^I0t6lj|aXjpV4$}_nZw=y^?l0I7i`BN^Mek2M8q;|lR22CWex1i*lz@>q z9tPb;2;ceSZTSb+D<+^N?HN|Wvc;IY1Wr8X1s9sogrG`~4Wtr3=r29#Z-L#X#>oc) z3u1|s+-ymV?8^(4;yFpZ?zXU~8od9c{ZtO)i$h&`n4HvFpBBwvHG*)fxgZ;NLf2(J zjx0NC>$(c>x)LDG6bGKM0mOi8sM)ED1Z#9&3#&U+7oVacs(i6$3zg~ZiZ_Pu&D}Te zxro*XaBD|m=+w<)z*IyF)Se2!TmTNim2a~iGfG;_T(Yh5rq}M_&$H5{>M*=17Us)M z0oO_Tz{t=Ma0}2IE;`bPIhildMrV0^xpJ_H)rlvjDO9YYMZadT`w=zZBJZ;(;FW-8 zv!>bd!ZkGB9zJH&tYMlg*Pif;V&=IVwSrDHU%Hx5?vwado?iQ79Ic~W_c2%xh>!1t zU-;f{Ay$E1$C2tWm3Gv3zPl%uBwYnsR z_Fwsh+xD3jcK^9T-)%Wp^zL2E1~v7QG_zanFQo$}>ZMTeHK;0#0@uj|IwY}LL!ELIDm3H^F-C4DQiS{&&~QR(sJSjheM%`O+@c7vIC$NcivUwijk zkxo2xvQ;k1!j|z4hWbm{bW;9k_M+^F3gJ+($?v3&4}YP@<^Z8^)i4ONwg+XP#app! z;B0294xM802p>WCXRdPho@u~`uu!YVZcgQz|J~zJqHt9YPj4SQ(WKox{@#QexN zEq)hgmP;2j-|uDbX>EC~UGGCh!DhEu3A$ejaDG$PIzt{#5F1b%4h}qH)BI_*N1AqM zbAU9mpW%|OT1iIm`nik&=S@sXl6A~K7D@Bdn&t<-6_8FZENsHEj)N;7fuV1lT(6qD z`^B((^Y-7z58EXn&R4HAYco!H0G4xGoe_L=(`^C<=9qEcds)ROl*;v_Zp?P>+55Xm zqmKO$83hCW1eS%$+&|&fZNqG+91GYnkGw7UHTNwEj7ZYYW3b2`oT1Iu6o0LvK~897 z^6IaAWHg?c8Mk-)^M>X8b6yw%bPcW{ud~P8fE$*8x84_TGYcGx)CnD&oSXQMrgWPY{(0)HKY2%x*zZ>|T zU{iojFV@m46^*#nWPU&K>2}DUs7}R3NTAXfyM$FlPez;cNFX$4Ogp~w1U&urIm*I> zQ$&WR2n=5HZ(OG+UU%aKIgJ}5Xv$OtUsq^9V;?2@Bz48H1$^s`D$-<-%-2)-eeRP7s32US4> z?12$w{xQ4t0)tX8BuV=R!d0Tqj%n55xA*eQ0Khe?q@rS+h@wXGOyKFV`}VX73<@e2 zejthRhLyVdY7xF~hJ~@#D}P?xQ)Y*1(iTq}$b|9@UDtPC&sEX;KU{&T@Lc2+z-h+) zYx+{n_%U;tC#PGnzXm#)2|Tw-*%@^Tv-$yHu# zLC)Ge$ewt9@;}pBg{u-vz|;8d{sW^T_!7vVp8s#lru*93I;67{kB>cK`12=~l6cD$r~6FWH1-6P|+FR67)=$!azr3XjDIL?`?YgFjr?Log< zkkS|F%o4P!46Mh2b=H_1EVc>5Rl=jxEGfe_)213~(Q$Ox=$i8sq%aWRYw8A?w)h=g z<_dUTZFUDZJJ%UFip7po6vD%ERE}XbS~^-VLYI9(4*h##TYr*fWsDIIdCkfH!^1zX zDsaFGO$?(XL|cx@IXCSS$6mfs^pm{Y>Qon3!vex+T2)dkHgF^{lg}l#kD>w}ae zQ0liACUeUgT`H1QLBgC&IYW?BtTQon^qfha6L+<2{a=PA6Z5m0!g`|YKJH85c`#Slz zg42|ZfHviv(&5XvrClo&t(5e7TeJm|Zv6|BDFM&kGaCMdf2W@w0X>sc*L}=FhBVqKwNpnndx>Y329rbfMJnRK_HyX$nLv$wKvZ z4W{JaPwOB?e9kK7=<=7^=mmJf_VL2qYeo> zR&0oYWrYL0amkAe+0N=wvXXzY^dS^|Z0K#54Myc_)g(N_V&@k1j$6twqG{i5HV{f38I&@k$dJYivA6TgQ-(-WpFOpuj#rQNc6<%dhLsQ#an9YE8 zKttDtHK~8j@aBomNQ<$oQe7>2-bVlh^vG%)> zg_w1y`qC6G8M+=qA6`rFl$1GK`zZ2^r&&R)uDX!3HyT8|=0nJ*w*t}uD!ef<*uXbO zc|T!M?CNNoq-sSJT(x(d`Nk5NcIZ`URz4iqq^e9)NT`uzTzb}E6WB}5ibF-qIg(Bvv0LQ_q}CgMl^lH8}qEgaDijEYaaS|L)O1tfEM{Yi#%nFLY$0M#J% zz>Z&G-OH`UJ5@ND;eu?vq}Z^kj`_tnPWWjl;MMapPx(I$+K}#tf1N%hxEfJF24||P z8TY0$o_X97H>X8kqo<>kd<=C7tUxMUL<`lL5@=(O$dWuZbxMU__gqU%1KG}14`4@l z@jpVngRkGH7^GETj77Fxt z?(^c`eN_hAvIBvd5S9XrF#y+rM#_IRgC_LZ}l_Wek*-;Ii zK3ZLi5^8;)mjR$DrA?7-@7Cab%!#LcYREwO2VvA?&W6(Xuw_)?c(YTtkF|QzkLUUo zg14qGUm<@RP6ej8FS%4yb$u35k#tUlx4mAwh$KZpc;tAdF;QJXo5 zqoOK_Z2@hh8ph>7ml3Ls9m*%s6p#Z6TNT6m6S${NKlcds@1Ct|cY?!N%y(~$r;dNJ z?)zU%mMu-azsJK%k9a?4DO)j<*vnDOUPfGmTcB8>bkhTY^ieXgGdVsuw1tz2yhf!4Yv!dIz6l=fm_hw9JkY z*P{FcQom=Sv6PzJehAc}-IAu{t=3$$vrMy^hGO>dnuby{tnN$L>UkwOGX^q{(GiI& zVQ#iPq+LWSn}k>J~LZaBgp2Z;vLYPx-#N z>ne*h1H4ECs-~zJh)lJsTto{P?(leU`+K>5nj%q>A=D#4%~wNuD>Cp$do+B~1SndY zX`sWP!H{Wakcq{z<#jMr=vG;g?Pr`l26EwH&&bMHHW6Mn?>hp53v&xg9b;I1I~;Ka%k&$GP*Mr7Ew>zB)_x z-xoznFgw>46(vttC<5`8k}hOq@`L{cl4RvJ`cBvDZ9o3}K|+s%i?}M-p0xEZIa|2h z#lEfw_T0l9qtv6K?wg9LMN||KXf@zvtl6=fVs8jjOq(*etPm27%o~nrTMnnCn(=w( z{K&;$$5i7DT7LK?Ni;?8A!}`>Y0B(lfzz-=O%jP4J=@+OqjN3Oo>dkA9s9>+nG=8R z;|J$|$IFlJdlGBTSpcn0rf4|*fVD_r3kVzt5%j{)Fe$jGNOj5L*lpR(YOBtn?0`AE z9i>@&aUf94x!Jh~y)lpgef(SK|UAeu~44CaSg4P;}YEtXO4+Y;{B@r7~lO zwvzG=M%A&~M_Zra@AD4P0mvVW3f8(T9G0ORxCIdD6q(lSVF&JL0QD9(JYaTX?AdSH zINLYqi+EGKs1a1=wNiha7Sp-B0E3Jh_EyL!+Ga9s@r*T$%nQ=h2u|b9N`r3SxzRb? zCwLev_3s&(lmNQB*V~{_)`S5k^voD420Lb|R|jvT3Sf2Ie$|dj&U#m$5Ir7JAQ?kF z|9a+`){^>Ucot0I_txZxyo(}4ltn}1y?;%b&6o&5$*4YIvQK9h|CKD}Dr_M<}v61`qBZ)*Z^DV<4AW+*;K|4O@bF8WmHZ!MFAnLjvbB-hZdGddqj%)$lDA>exrvrGHeNh))9@ zB{ForGmXx|wsEKTkcbIIYmaE$=(-@Z7WwVJ&y`L*kBHc zfs|e=;b3d^?{x&aDl@)Cep%NuHQ<}w>2GTx_t|?Wm1>lXmLs)&+d9_t6$lf1A5kgf z7`Nh}p3~Qzxu)be=nz+dc9A3i3I;eb`5*S?PrpB+_gI^*Wh-fm4Z zXxubkKAFfHun{*sSV^=j{h}2N~%Y8T(8L z#AsG{(>`p04hKXAJv*)~-t~fLY5e^6f zK>TgXGkXHYky$`mb^bMp(%ACiS1%em5JEjPgw@ujuRJnxUyeob&qd=|+7|a_j*_*U zRQCRw2UyO=$o$P-w3ge__-D1{m^Gi^Y$?5@S!n2S&RY!WhilFH59b+oV$n!;*gCqN z?HtN)Fh|oRa={WLOBlnv)zoneu`-iytMDo30c6=Md8KpWb@OI=YE3e)6}msw8{zvW zr#lBf3uALP7gq$SqnQB+Npxj9?Bsk$py#symxZt{L&xD&j{m;@=*H;$s}_uk?EFvl3A3@TQB;8-KyjDN&p& zLJ5Hk9GHOMzh%XEr4@7us-1t$_p3HG`RdESf~!H%)LC|udJcl$X2a>Z8=)Wxm5MGV zVe0kmk`Ne&1;_<8C{|#lk52l<;wm*Dpr;8Ex7u3-=%9GxFpBuE&QWDjT_R?7<(A|A zP!Mr5)Tu#Sp|iR`V;^;#{ZPQ?tg0$irDa}Jchgu~I-f5-RIA0uEa%|h9$`yG`(D&R z!>yviiVvBHCLt51=BaEBjSCq;Cu3IUt8$$yp9@1JfE5@?N2DRq7wK}`7Stx>z>NXr zy~UEo%aoXcR$#!K1;hR@VhL+Cntvk6MW{I1mRErQB$tWG6>}9QuT+O;+MFp_s@JUM zR8|p}loTPySvdldKCD9RP#P+hvC5BgDnI8)RAhB>hZrJvXy=)?mx>NhR7vDe4V*`L ze9OauD|LEG@HI9#(7yfI(Mx?0mu697jp1AIQ{^X{Hm@3lhUB1%f{3jAAvL0v9p=A6 zR85=|Oh1JM5B;w;pK~K9tEJGlOrW8MwG})#(990$;|q% zR3_?I@PC!9HYo~&U9<%wv*lgNviBHZ7Xz9I1K>Gfr_(y;1hRDG8J z+T+qR;j`9IFl}_*?#_WW(Uie#jK(AzMGd!$p54X97FpqIc9j|P@2vXY*;}5jAR`Z%m3o=1sP!(Osv6!5B)qPwEH~ z(q9=-_xkUYbV`wBfMu-t@>ACe_l7E6n+zk_Qik<*5bb8^!s=6?BnhRzlnJY?SCi zqO$MG)W!uGETW4}F_2`L4PzyR9WaCw{+)^c0l_w*R}NvKMO-dExcO@i#OQCE+4Tg> z4{OXY3a#lfVf{pql~MUs_eutHF5QQQn`63~EmgEz!F?1WsV>T!H`JJYuez!#Dv;0% z6BZhj=@a!dS!LD{RDH#t)@X{(Bz>lst5H_WG2(S+hjAufeYw1JyP z0#x6^23`KIxwCp``w7~8fZ!I~Ex42d1&R|OxNC8DX>oTc!M(VO2bf&+v?A}=TFCrKOT(%p%j2L+;(~970ju|<~4hcQg z(}(H)4jFpIz^|u+s70#OX5p-I^?m&-LSSRj7!glsN>iwO?-_oh)rTlvsx4_GS@DRg(e$j&SC&JLeK5Ps;LOuwA~(lwKH z0UB>mJbx>YncBEsRT6;bRL9a7X^{dggvkqBb2(b61V)US|(fn zDNV`CdLZaL<$kJ128;r(`e$BuU1?G1S+{NY8`c=3^ zYxrM^S$WF9%xp}Qb67JQpYpmFZ5#~sX%xIkOW1wrnN!9}^m=eD-mH2?^ z@~TM18$?i(-SXzy*HZ>pq`&AVg2dd&rALx5HG(=mX>Q&I9@#{cAx&#Co<(Nxh>c4{ zt#b?_(a2weO;m6eRUSLm))?Sv>kQXFhFVRFAz<*L8S*dOL@>UB|eUFnrl=}&X8W)5MEGmew(N?1T z@M+a{isf5I-&GY?HqU;p2FUuM<~H+uA)#w%Ni^oo+jhd=DF&Iq7XWcZE%uCdI(nPu z0&%}bs4#|uAm(!ycag|wvn67GE(s{_KOxg#TQGifS}-<2fLEk!vIypAlzP^J?{{dS z91rCYtN*H{JsT(imHw`c5wsFCp82DKWe>!eSf(;&yvI#gWC~dH1xPZk0#_Sv5DDIf zyuYacWH2g7`3Q5Pvk>T@wy{Q;jTV-nUTXY$1#iq^>4k~T3J7W_HGC*92W3K<7oJzX zHDTTL3S0$CBQ5}*xv1VC7ABb`VFHBC`i`oM5!dY|g=qkpH07BrO&VyCS^5frBfYkg zbk2sF&vg?ICbFZwLRVFt0?josELoo+_0TcN`Slss2kohpcoks8dPjjpH|5~lp)WLC zwXX$~K^T%6bCkV$bSo2N1CTL^3Go&Dh^|qL9HQDSQ|HN%tvKflcCF+PO@{YGP{Rq> zvWlU)O+^lyu*(bo`xB~vy&-V2K}_3ObS9MGNL)B@S)eihK0gX!zk<(@LcOCL>}2*p z58ff8d83WR_~)_De*TB-fBJFVWfrzDVpLf;*v!-C#;!vOcw=d6770r;v$DY0#JD6~ z6q1OPqT7Kg%U(-T$+w5E3FG<^+T~m{tbcIA%oCp@$Bt zrOX6RZ(We6VNr~ifI)|12 zKyB8n&@ggFqL{LZ*dUkVj{zn~bQ7d?AAgjeE_<}UDUxNW`==5l)|l|J;CT^y!YjE{ z&rzKHUamB^%{1pPDySf(+`4xWnd*6jpq9MLe6EDmy6PTdwXubN#$VwP>D{ciMFNQn zJ!=C)Sy*7^IwbHjvK!yEyeI9G!NU)n79}ai$%x9BYs7_3gZRKkM{{JV4)7ie@qa=@A9#KS7=M?OnEUg3fRmhD3;$##WbA|A7fh8R5M{{&f%K6R^ z09WFtfLzTn<{$C0zcs2-6v1ltX-I@Tt2(s)5kIE-i^7ohV5a=?t0Rz6GM0FCK&oIl zR+N9gY8Ju?Kl{%AJ)-63C77tweSxf*O znt^NC{l0pR1)9f}_3mzWcQe24)(uw$M1X_T}uG|WZ|AYaCk%km)HCgzJrgMStgC=@L+V9Xtv>?*4XaBz{`?QND? z^BdzI;P;?e-kqraSFJtPWJlEm;)5D)sNoanY2@x11N)xpFe5*gV$V+*hzqIXt5~=E zI|CVyqfz2gX5;H<+|1kbLaGVVq-5#&F9EQ_&dMc~h>1{h3j~`?hAd4@-6j+T{a}iv zv?0Y7RFi7_w99RSkNa=Vx?BSUpT*97)rxKgF?h^mmH-&@oF$|Jdx|Q`v2dY-o-uC` zj6M|(1g>-gHR6UYxHV-lA4w=$@FXv)3DgJPa;9a&2}Z;5_ZV*vGS~@_SQ}L^HO2!Y zIh`9Ci-#T-R5a^MOt!KR0{2W|35Y$mXF>^!lG^`z1RG-EP0@6L1f#gWxl097f0o)I z<4E?l+ofqJzJv=2leI!$Sqdo;1s4O0or~Ui8 zDe}Z9cvk zS*@+yCBKt3T2lS;@K@fTR8j^4y3&?wk1GYaTG&O!HQ)JwOKn4Rxx3_mecb%ID zu=wFJISP2O92xqNzHE=YjE2xaz(|r9tAk2MTViY?MA4aULGJzcguG&lU%$~_9fXE< z9Nj}JNa;~C8qj!G5O4(gdYsqWG3Ct(G-FK_EoN+muSpWKkn0jngMdE;@pqqYoBwBP z@~~ko9eBvT+owZChZ93l$vdMEAQ1ra=nL3!C%K=WaTtdL>%Fqt!|kw(4VWKne(kG> ztCD+A6HogXuy(7E62Hp2MkXkrU-Qw#F-P$)B+o{WT9O6~Vy^xzX9HA9WO8wiZru#9 zh++s|k^A?ya};+<5_@RQB0unD9a=HOxTu}PGt}ztcc7uKmDptFNgRgv8orOtyd@@# zWhao@k0pm|pg}}Mq0wzbB#_NE#gMMcdb8R3TCf6;VV+M{NE)I2V20MKWEy~ox^~Tw zQntI#0~l){AVo4Jke{wLyNZIOpzv2{zS1%U(d0`GNNSuyGzMtMso2geXkGAyPuB;T zDtn@^$W4tk@u6s{GYIgq@K4;0<7iAD2sBi<<7oKf=SNBlUAG5E0=F8wQ;yT*8iN@E zgPV{ICex)7@E;~nXIK z=~iIb|8bzuaMNphBPLVgm|E?5Cb2o)68^wx;_f7QyNp+PSxC|WRam+=ouR=Jy@fk* zlHExCg`P`*IV;`)i*5ow4| zC>YgZ?A%4+->dLX<-zdbLm7AdHiBD!u6CiRft;f)XGAgPV3|oo_*>(ZUOVtWUle0m zS=q>Y8w>Dn3%ld`e5ErfUzCaj$4447sq)vA9C}@!x1|7)eFZ%Y^1QmbfEh;~tf%Vi zgZcSS4s(fK4AeY`^`F@i9YeE3a6T~G)ofIsqaCG!W}8~C3>4Hh^&Tts^QaB2w-CpD)^&hRQoR}=P!zpxaGlgLU7j;Z*AoI`=^C=ZAM7ZqhAK~+GSPzNz} z*h`Kdbu1-ir_&go9LJ<4V%xQ0*Pnm!6TTY&?bxy4yVwk;RIL30Dz2Nm8+q0?2}CdmYJ~tHtM}zN)Zc*}(5}0~KeL+RYNis2qQ859HDbiO0JT+i@KG zP)aoi)MGGQb|4kshTz0qLpPQi*`pJP`U;lhCf&Jk#PPvobu#pZY|NCpQOpk5EsUu} z8KD)04t%adO4+1z?I0IEjY_FZR~%-MJ_4=uGONtK2zz7+fO~9~%LWer{fe@P)x~aO zZl~Kdg-PQs@d{2k3c9zneSx?*A+80uU>yOmoH>rIxJYC8dn1~7hOh?LL`Hl2(LfZg z{OFtg2_*3hBz`a|kiqMQqb?7Cpal_nF2aYi*@xVVN4vWZjO6VIdr3nVZlkU&Hy#!~ zyzl(CW3e1I5)}(>MDYeg$yauOpg_qK*eN~Y03N+gO+EvYHWevQ1(VG>TMs0;P}C~5 zmW0pbb_RFya!wAP3FgkmUz?Ht}vuY;d3#V+eF6@$>7Y-k9E(?m*s6%5V;7huuQ zfo*;*xe^ON>7<`k6zh%R?BCuEoNV0nZeZcWbx*ENs8hU^!T$~opYuOfSebH201tL~5YnV^~Kg4a1#ec6WUU;9GSkN$1{x&;Rz%P+!Z)Qas zg%ZdIfIk#C$o%y>pX>Xl+^UahqA!S9O2qKajBr?c*n!7O)zpVsgw=5DjWxwk8~bs!Ht7_6y-jHBKE)2F=Q$x#YQ! z0w=%DlA5ut8NTd6*%o$8aTJ#*ROM(4=B68Dq9@qM@hG6c&3wjXuTyMgzluqvI~J5DS1c35-br11emiU6ioppijNGL%Vou8@vFbbA{J=RhicI< z{>(DTx+*GPj2SP*46@BRr!)RlL*FDfjlre4Y#|#HL6=T170anxu^_0;MiG1u{is}` z!x^dxlaDitp5iwfRfYUyurF%VUs%XP3CvN`JcGbs7{>k7L!i-w22bgw!k(E75D5xI z|NL5m%~(iXQ#gpfG|PZeMHAlS_kws{;4uhC77pwJE2!8gtb^?o+?&BB?3L|GF{KUB zIj)Hd_~Q+vB`&f(rdl_jyI+5KboQPull`Ys2+8Buoz-SPiNFQ&dq`jB_l;Pn zn{*x{#$NvVK5+B>Y%`-=H%%v+wTv$hjMLg zju1bo#LY(d2s9E}Q1Vn-1WdtalqxsVwCjFjcQzHVQ|U~GI^3IPh9wq?*@4KaEuXXF(=(n#! zFaGTj3m%N9?s6-~RkcQIW*}$>S8!*%Q)ecynuFMY&deJ0mffeVerouR2#b7xi=0)y}cyD1!;f_f=WOc>6e003 z-lkGu9C^^U!#2&*Kw5Jpw->DZYZ>MVjEOgH48@M~F-IK}#1?(nw4!*DFC&SQPlzf+ zQ;T}rTlg!8Uw58_1WW(pjB|a__GSC3*4@cuO{ez$pDM=B>^%ZvAKSi@gz_Bnpsp6@ zem8GqF<5zdFHf51S10^M75-EuN-4pS606!|mJlT~&w45%9pPMo;kV!B{pR1tl?nX* z?IC_S2Pu>&8o9j@f(iFNhfMFUEO#R<6~$wIX}?u~ilU%gfC6k{8e2@Pq^Y=~R}Eht7nq{<)7neJg204F zCPx29J(mj#=U}*)Z+Nz}bpQ5jzEM`kRrXUgv!S<_5I=#W8^ql)Ctg!f8uk+hY2L>4 zWT#k0My=Ak+6mv{+Z4%Nki;Q*VBbgqVB%Y(Qe@6lKBKnhvY;A)_$3T@q=*lP83i4s z_ze+TOi$)c(JjGa6|u-LK%7n@+c`YACGgg0j73yBE%X}mrMrg0 zynAErzbMvtzCo$16gg1+tHgt&Eu%giO(=4}MLs9KdrQ-A8OfeUPopXLA@RVU@Csy<6Wf+4Q>T5p40@ zF=#Pr6a6sQYXX@eLq-?>LB1l`;LhT1UVr3jsg}?C!FH5|u*r+U`rSxk9+TvfpE^ry zo&i?cYH3?U@F1f~6DJB=QIGTaI;+CIVT` zRDO`7$tC(vFEM{VfZB9Z^}ug)*3{{5Ozp;s2)!23b8qiRMd$r26PIonfUhBj7@!fA z3y5C;uW-Z$awPE2dl%(P0kGg^m~eD4$r;~MZx@UvF)545gNBtk9FA~o(+oh!+x{N7m8# z|D-e()NuefeDbeDLe%pbxy#T((a=HBBsn?ufSuR~C-8T=Z9$lUJ7x3XB zHOSZ}BNbcOTrgxt8y9tGgI`<)jA@jd#C8h(gefvnrkb#40gY=jiH=uA+sq<9jFi`D z2P)zG%B`rK*0q{{T@(k%Tm+by6vHcZ7_no;0^GlNoe*b*n6>D;J9kBd{)CI3$YW=Y z#z75qu?gg$1%pWD!qbqrNyY@NY)QGjx?^0-Re)!xAt;T`i62;SZermpZMd#w4(TkK z<3v8v$>+AyX3Eo*;p&J5X~t6{hgX*3r=z+>D`26_@&hpp0?t+iH?WOXO(K>39$$Pm zu`8YQ*#xEU()mpY!(wpZR;fkfsDn2IFPOM|z~C?0wmO>lU}|tQoPabIj&q}mY%fqX z3_+Q8e58#sDJ}$Mnedk-{?p7ywqC6{ir)G_YB{#8Q%)2UZb7kg2(o;bpRc z;<8~co?0JM#=B+pe!wdWxI2-)+a~)?leTp>jlh)(gA(+0<6Zb5w(ntS&hv508*OAQ z;9$A?&$`t|nwuIuEJIC+zL*9Q6zx`zAP+f@HQ&GS#Lv=86`A zfSew@3W#w;`EMeXZ{%L$++pUZg~1hNv;f3;q*OLtd@)vBV;r0j2jIlSoz~|ZwzsF@ z*U$AGcj?N{qe_B+9_fI8ek~Up1~Dd%zj_OhLvIvAnB+F5PMQ!Bw?{T~t^Cbmbo@%=P{ddqM#J0rN z;EIpeN7ER~#x8xpq^w<6lN@RjX?U!OMa}GM6|794niN_TO2tq!4u0rSA5R+*N0};$ zYbETn1;XKfz#!d@X*CJPaeyzp38iTiG`T9T0@_BQW+z0{0UVN!JY9p%r zgF=I&YEp%zKQq#Tp`}Sv%PW zRFMvW&Lv>Z9T`eSdjKNtZd%o(xbBwT34#j>q6XjFo<-$?JiNK8jo07=2^n2lTe5z;k zO^=iFU)PI#e7HRug7jCR2bBOcbY7qIO$%%9`@te@R8K3W;mlFo@?y%_J z#NiUha0u zbai`fb35eRncbXl)>QmrkWnETOw6(vbB0LJHn(Xlu&~O!FSwxQ5^@ z_}tf*1S<}+q39FaTYmj1?ctd<%HTm+M*;q>eoJ4bW_38iOn%B&}@zjA)C zP-3U#6IX`7vS|qo!v7jmXwl#vZp{?x*2kk2jxp5H!q{4!q5aA5#jtQj=4^fNj7 z(G11w3f04S?(6y|!|SS_|69W4tW7oS2=LD4`-*#(nJ7Nl@*%EXlr=6xN`|T-LumFc zgYM<(AFL|k%Vz@Og*hRHFGV)!Q*x@(sEAJ{d>!t;_fjbdiJESA#<#bu8x4nxOPRJ{ zY}saeuF1pfI`5Cx|A>w1^1cjwRP8ghRaZk21$ozu9p(-5$OWTYQE96~kN5JJtC6OV|p z5V_71lEt$y<#&dg>7+#y&&uF}>g%k7K}>B&;gWAUH%JO1){CB~;pUo ziJRj{Dt2-&)9RIQ48Zcpb>1A9*1U9GUA;TBu?#j_A;Y;33+HS{_Rl|aUuVa!^@u9} zcwW+0dN2iYLN8IGqZP6ABx-w#EQXEDd!ZU+mkwUa^$y z;|-p4l;j1)?9P7o--Fke+ceYejjsPQ+v^Iv_X2&vF*iLgw4}$&_V8PNmpW|pxO28_6FELUIJ<4x z88P(M%m6Cpo}9`~a4{p2nexYt`1}BL@cd8?r;eJJoN)30!u`AWG+?a!Za>pBq}ac} z5@E0)LX{8ay)4}N)SP?)@_3FaQHak@Id;e8nNO_)A^`Armdfk+^mK#IR@yp2K&vjt zknLzHbP14WqtZ_CSz24Ds6<+vE1G1?VmvL^y&xPp#C&vHOY_~fDd#0^ z%7%$KCG9<>;=bA0=Wh}pU4Nkdi=7XF$!+)@vDS{$00O_f{9z3^mr&ji^a+HGPf03` z8PxU_kbTQ>ju00K>ZAqH0HcBhpmqVeXjE0G&FI4Eyc$#s@wCOR!zcCCIXJ;{~q=p|2opJO{s3qKJ0n^6a-@wWcSy&1TNj;(^ewf z0z*n~iKF;$~sno&9 z;^Cof>S zz3s^=^`jD2JmigEg>;T0R2)1iWP@<}m-$IjwdiJ{xuP`@b3eIHfkZuN=%-0>at;el zZ2iO=5S$6m8WxRG9+1OQp?zWFvp`%}Rwdn>PE2!Ea2@MNtbbwcHGC+P9 z*SdfVd83Hx^mrpiCuoL3e3UC^1!%2dCpe)JB0e3#)Wki0PnXx~FKMYB$l{)aPe18i_**UzYeXW2Qpey+*5N*t zEOIBik2lu3nM72q+FnIo?-zWsBrY~BEAm)c@LK4afWewFGd%h^*y5DBZ;HK$>X+X# z?JN8B%cEJ4cDh@1B$^Bq8krnRFsf^Bm*Fa7p=Q$hVbXl05N({pXTi}1#z;osKo3hrEDCj#6`rOYrPj`I@oph>4E+FU z#tn2aGvf3uI=BL){Xq@0007eNl#urH#la{}YrC;Y0{@Xu&mD$)|`)Wn??|IsP z`{r^aDb}uw-0a}Ul;E4+!P698tXYS)q!hGiV}}V)iYyFQXT3mYbW8!aBM@13w^7^- z03>K~Xxfq%HnF{@k+Q7Y!CTc|Sl1su zQDQ%K32H}owECY##Jz4*etG=w#&*}k6<@Y$*{uwzYaiWjez?NPgAbUFX|BDjd>&@gHe0WR39Vke? zb$&3!)r7!}W<(YjwA}q=3$`UpY*r}Jf?8h_9bG^OAZilki}-%k18L)q1~Upk^W1E`y#@NWO z@Ky%2QIaqZ%IXX(Q03I^_K(3O@i4)o*dtPo$}L4P9K5P+hf0t9-lx~orfn>jIy(_05Qba`WBLvEAxp${2JGzqb=($xURh?M@EUpi_vzx_O`PcUB$1*2@Z?G5 z?JADseqk{c0;2_Eum`a=0oxferwf;Io-GAHK@$;0E;bsgMxsW3cCHrU6Ykz06fCYB zSOJt{&b8OgpP}KCvx+9jg3fZv8OOj+91FW`P*7sPoICVwFLWMmF1I#)O*a+Ke5~J! zU_N%jeD}k{2^=jAEcoWZt~`7zSfP{JJYEXpC#!Njqbd*jr>=HxOA=0Z$ADYFO zeU;ClF6)XUvU5GQF`!ajxN_-ejt@n_htS-rbl764M-F*DmNR-Uz&?}B^a}xl780i3nGRlAG7cTr} zmk}KMar0sOi_kskEiSf^(d+&mw%==SOSj7ba@R$A`~7>OPNQo0D2&bzE#@DF*6);1 z-5gbe1O|Z0(1VXhJZdhUOtk%PR~}#y zAL|W0ovtOQ`1~H0e$Cs3(*S|ygk*unfm%|(bnvjVK!THzX+)MRNR`4!@yp zZaF(iJVY$Eh^H&>Nw_lb1Jwy{$2;0qLK4F9u`>!>!BNs&(RSGB!RNVr3*36Mhw0zz z8^6t@`g;~|OSll-eM#YU-~K0z=;C=M_bt)u{pp53{N^=WryB?T>4i^V!AoWBI3rl6 ziu(<}>en>@;4t#_c1P8D!HcMHV1%erF}ey6!l-P_6!CS{`?jqCve4o0iY0i^HihZeP5jNs zkGDg!E-QI~Jmz7+e zJzQouNG6-Itat_C$HoNzVzG0o{0f$XGhfg<^SjM2n9 zvjEG`5V18ju5$i;@*0uA#iL%2o> zgV3Bz&hvaSH|b>b<7s-1+tS_>;qG&AsFw}ZKCd2^yHU}>SMHpR^1fJ{N$prdIWuh!kM1$9QrCh26!KIb}X-nVRh;!{n;hx)e6gi_$t z=`l7-%da@zKi5{*PNW;Tt@I9YH#-2f2`KC>f*5kB;4!lT9ky+W=YXc6WR=++=AEjpixv5rAC#?F3yd)L#U%acETz}5D5m-5!@=E(*6nIG-K zXBhEJLq7!L95O+i%K|o@-gHe)j_iDp=<gh3Si65W5Z6nuFOM zaZj6h^s|Sgh6F?+X7sxef~*_8VU`(a8bB`9RTE;`a@Q3Xa8Ma{_N0oxAxsb2m?7_W zh%B-0G`;7VCep(gzW15Fnx}9ife+_JIgJTTjqB+6rSQ5JyBRh8afA+L6Bn1^dEv|R zxHtc#g5xLu@))F-^Y`KXMTdinl~qZ_*>@WP08RR!;WN^>jHr+r!^9Q59=Q_XJ~r=f zK4KgUbke*{ndSHY$i`~WH?y|6)0o01#?V0;;K)e2{6w>p%H1K+hm|H9UmuC$p7b)lKyQh_nz; zWKjG;F_pS_^L5V^L~*#ZoWtfB_8O>M%dzodbQ-K8gXgio18%Crb6cgP|NIf{zdmS* zqu}SN5!MrWJytT{SNWCRG|xK(^!qf;=C1lS#u(PiMna8)ju{m-i?PaXvtfZvm_(Cs zM`5i{kyCz`6_#m0_=y;F*OCo`L~pcO%K$baV0@f}T17E>OC@J-_#vZ8E9vcD>T-o2 zx%C7;J0vzBB4K7kNEVTCiS~zeklQQc+;ZKyPu;x`{YXweGx=iWIKulhDd#5*YD_7+ zXAcD(FV0)lEU@mfc)k=Lb&#~zNlI-*d8W20r3u~Nj(21_*24&JhHLzxf!2uPrECaF!^cq+zPA%f|7N(`H{b zJGLmJ|Fzh^TR9-9i}*KCyRB3IrTntmaO0-7dBo=mYc7j~ZQ#o9ord;Rpf!q#@6E!I zpWWAI!sh16(MMm8(mxxTDfiI^Tu!GXI?gm8XTy=_)*I2<`?m|ZOOi5c(_z~pLtPRo zZ##F<92U051MrqMgc5hwU4u7%wTYkxDdo(i8a@1~sklfi&FTE!bhi9)$5jBiUyqj| zbcr5PAUA?ao1eZd~N!yW7@KM=a zbRe|qm;xcbf*Anz9%hgo+@UUBcWZfcW zzFio9;B5kiaV`3)UI#|+MMEA8f?g~Hhlfl10Sym5s?LKQNL6uMZgsZ)aN^P8W5eou znsb}_a={~g8jKywmiiT^JYm19%oOy{B0&A<%SofzHdZ)Kp7Ldfi9smvI4&v zb0`Xm=H)4QeswfCF3s*`m|PPqvk+}xlTYxC^WmlZ)YJPyzgIPTzw zwhB3C6lj6I!L;8dTLF zla;TVTs3gOM2|(;sC8;hROKA^#@^qW)YU$cJt#Zd_=AcW4-y5RB?nnR7jRkHx zT&KBha?cJoY-Yl6EMER@3eX^Mq@}*&QWA%no+CpCBk&kSviu*t@w@!r#G}il3(-Fs zd&EK6GaWVu*X$_ti@X_dC_x@{Cm(O%$mlCP>nTmX;A_9vung{kN zOh6#S!Y*YYwbD)3ySt3a3fMQq06^E})@)K~4iz%oWzOm8V0BDW3Z#w4&P;<4{NbWV zQNW>%nCGI(YQF=41V@tT2o#f*MC#zZ?oT5^grk8(S64e)c)w z0vWj$FW@pLC3U*1O8{;DR}CRdRk{$3=X_$dMjk2?xG{hC{misGG&EjY`)vw{KZ3K# zz_yWhQvs8>&d3WpzS|4GCma;~5gg22Zc%d>((T|vk>7tC_dML~|CFa(aEZkfbXl?+ z_sXH*VK@!{!@u-zAGZTPNuxB=pA!C=%?S*rbVTsY-lu|MDRD0LEdTvBLO=i`_J*jy z?ZkL2ju^3tk5#jpm&AAc%%Tj8`j)_m43F`5l87q_I&kTu6IX}6=O8W|C()c;C?J|R zYi7(^ZMjCiO*foM$jM9*;`@lVc>UhU9KkZeA>1-)u|CMHel6QAaq!kwG1YW#OWWDG z5XrKUojLKIybu>MfyoH~pyVX6;Gnydu_6#0XK|=BwYGMt#bpq8KX-bZ7WyeZWFl)B z`tB{pG|jqxlM22rsXReLU1c9i3odMyZ`3kd)0tB>rctnEKGI4G9DRA@ItBoMi?UEL z4MCf=G&>|_Wqnm3DYw7Ne7?K@#(mQzw6V^rwGHWLFC8+Eh2)7OIk^KmRcS%Uh*2f;su>dF+_ zzYi$>Y;F4OOeAgAg;unwJ+YgfIr?~PxQ<33gx199$fVktX0Yu^3We$fzMtSHQ_3(s z&PtlKF20K$iKWQ4cf0$YguF!PC+)i<^6S@96p_bJ6WKBWj?QUwiOc&SnB_GuHmF>e zsQN@rjwS2D@38?wAs(I0_j$Eh{+G4BLyZHUa=rY;ns(FV)61Drm-oykFUfzui9{|> z8V{xnJUg#&>G;B#2a_iRYgOTJNUR#09n{wt=*$_w=YoZ4dX?nr+#kZuMw z1-^!Ip85YyIQdAT@k1&Z@;7Hkf>G^QcM%xHuzmFg6WCUB4SJKa{eX0q!(Ae7gLVU7 zxX+)W1ULCSEUi`t*cVgA!3uPZ+ELD| zWJrRH4YX94@!#8SfF5;9poU&3oWG`T+K^x53NMhY!KPJTnu0f;mbXPFuCGkS^*&Rj}MQrT;_Z&i2cJ%3h z-Lop9t$BW>%E145C4!HpoR!2Y&F$Cf@p0(3DaPi@xjgdo&-?U%mz|5;FPYb=?iDH* z=Su4E01Zt#b6lt~_&rw*{ZO;b&g$yGpu0fZNq)fVi8&XjaJX%hN?2H|<^A^X1T)vjNo`rp1Schw1kh-{(@~XKk#+H(stfu17CEpYL9N zCeNRD`iS%(LbNdPZ54@6mm*=}`6^5uR?I Date: Fri, 8 Aug 2025 15:19:38 -0700 Subject: [PATCH 43/45] Import and export support for EXT_materials_clearcoat_darkening --- .../EXT_materials_clearcoat_darkening.ts | 118 ++++++++++++++++++ .../2.0/Extensions/KHR_materials_clearcoat.ts | 13 +- .../loaders/src/glTF/2.0/Extensions/index.ts | 1 + .../EXT_materials_clearcoat_darkening.ts | 97 ++++++++++++++ .../src/glTF/2.0/Extensions/index.ts | 1 + .../babylon.glTF2Interface.d.ts | 12 ++ 6 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts create mode 100644 packages/dev/serializers/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts new file mode 100644 index 00000000000..4ae75fcb0c1 --- /dev/null +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts @@ -0,0 +1,118 @@ +/* eslint-disable github/no-then */ +import type { Nullable } from "core/types"; +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"; +import { GLTFLoader } from "../glTFLoader"; +import type { IEXTMaterialsClearcoatDarkening } from "babylonjs-gltf2interface"; +import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry"; + +const NAME = "EXT_materials_clearcoat_darkening"; + +declare module "../../glTFFileLoader" { + // eslint-disable-next-line jsdoc/require-jsdoc, @typescript-eslint/naming-convention + export interface GLTFLoaderExtensionOptions { + /** + * Defines options for the EXT_materials_clearcoat_darkening extension. + */ + // NOTE: Don't use NAME here as it will break the UMD type declarations. + ["EXT_materials_clearcoat_darkening"]: {}; + } +} + +let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial; + +/** + * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/2518) + * !!! Experimental Extension Subject to Changes !!! + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export class EXT_materials_clearcoat_darkening implements IGLTFLoaderExtension { + /** + * The name of this extension. + */ + public readonly name = NAME; + + /** + * Defines whether this extension is enabled. + */ + public enabled: boolean; + + /** + * Defines a number that determines the order the extensions are applied. + */ + public order = 191; + + private _loader: GLTFLoader; + + /** + * @internal + */ + constructor(loader: GLTFLoader) { + this._loader = loader; + this.enabled = this._loader.isExtensionUsed(NAME); + } + + /** @internal */ + public dispose() { + (this._loader as any) = null; + } + + /** + * @internal + */ + // eslint-disable-next-line no-restricted-syntax + 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 { + // Logger.Warn(`${extensionContext}: The EXT_materials_clearcoat_darkening extension is only supported with OpenPBR materials. Falling back to PBRMaterial.`); + return await Promise.resolve(); + } + promises.push(this._loadDarkeningPropertiesAsync(extensionContext, material, babylonMaterial, extension)); + return await Promise.all(promises).then(() => {}); + }); + } + + // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/promise-function-async + private _loadDarkeningPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IEXTMaterialsClearcoatDarkening): Promise { + if (!(babylonMaterial instanceof PBRMaterialClass)) { + throw new Error(`${context}: Material type not supported`); + } + + let darkeningFactor = 1.0; + let darkeningFactorTexture: Nullable; + + if (extension.clearcoatDarkeningFactor !== undefined) { + darkeningFactor = extension.clearcoatDarkeningFactor; + } + + let texturePromise = Promise.resolve(); + + if (extension.clearcoatDarkeningTexture) { + (extension.clearcoatDarkeningTexture as ITextureInfo).nonColorData = true; + texturePromise = this._loader.loadTextureInfoAsync(`${context}/clearcoatDarkeningTexture`, extension.clearcoatDarkeningTexture).then((texture: BaseTexture) => { + texture.name = `${babylonMaterial.name} (Clearcoat Darkening)`; + darkeningFactorTexture = texture; + }); + } + + return texturePromise.then(() => { + const openpbrMaterial = babylonMaterial as OpenPBRMaterial; + openpbrMaterial.coatDarkening = darkeningFactor; + if (darkeningFactorTexture) { + openpbrMaterial.coatDarkeningTexture = darkeningFactorTexture; + } + }); + } +} + +unregisterGLTFExtension(NAME); +registerGLTFExtension(NAME, true, (loader) => new EXT_materials_clearcoat_darkening(loader)); 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 42235e67f3f..293efce7bd4 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 @@ -8,7 +8,8 @@ import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; import { GLTFLoader } from "../glTFLoader"; import type { IKHRMaterialsClearcoat } from "babylonjs-gltf2interface"; -import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry"; +import { registeredGLTFExtensions, registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry"; +import type { EXT_materials_clearcoat_darkening } from "./EXT_materials_clearcoat_darkening"; const NAME = "KHR_materials_clearcoat"; @@ -80,6 +81,16 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension { throw new Error(`${context}: Material type not supported`); } promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR)); + if (useOpenPBR && extension.extensions && extension.extensions.EXT_materials_clearcoat_darkening) { + let darkeningExtension = await registeredGLTFExtensions.get("EXT_materials_clearcoat_darkening")?.factory(this._loader); + darkeningExtension = darkeningExtension as EXT_materials_clearcoat_darkening; + if (darkeningExtension && darkeningExtension.enabled && darkeningExtension.loadMaterialPropertiesAsync) { + const promise = darkeningExtension.loadMaterialPropertiesAsync(extensionContext, extension as any, babylonMaterial, useOpenPBR); + if (promise) { + promises.push(promise); + } + } + } await Promise.all(promises); }); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/index.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/index.ts index f6d80d8a0c4..b1f9bd36be1 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/index.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/index.ts @@ -11,6 +11,7 @@ export * from "./KHR_lights_punctual"; export * from "./KHR_materials_pbrSpecularGlossiness"; export * from "./KHR_materials_unlit"; export * from "./KHR_materials_clearcoat"; +export * from "./EXT_materials_clearcoat_darkening"; export * from "./KHR_materials_iridescence"; export * from "./KHR_materials_anisotropy"; export * from "./KHR_materials_emissive_strength"; diff --git a/packages/dev/serializers/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts b/packages/dev/serializers/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts new file mode 100644 index 00000000000..ecfee3c8bc3 --- /dev/null +++ b/packages/dev/serializers/src/glTF/2.0/Extensions/EXT_materials_clearcoat_darkening.ts @@ -0,0 +1,97 @@ +import type { IMaterial, IEXTMaterialsClearcoatDarkening } from "babylonjs-gltf2interface"; +import type { IGLTFExporterExtensionV2 } from "../glTFExporterExtension"; +import { GLTFExporter } from "../glTFExporter"; +import type { Material } from "core/Materials/material"; +import type { BaseTexture } from "core/Materials/Textures/baseTexture"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; +import type { Nullable } from "core/types"; + +const NAME = "EXT_materials_clearcoat_darkening"; + +/** + * @internal + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export class EXT_materials_clearcoat_darkening implements IGLTFExporterExtensionV2 { + /** Name of this extension */ + public readonly name = NAME; + + /** Defines whether this extension is enabled */ + public enabled = true; + + /** Defines whether this extension is required */ + public required = false; + + private _exporter: GLTFExporter; + + private _wasUsed = false; + + constructor(exporter: GLTFExporter) { + this._exporter = exporter; + } + + public dispose() {} + + /** @internal */ + public get wasUsed() { + return this._wasUsed; + } + + public postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[] { + const additionalTextures: BaseTexture[] = []; + if (babylonMaterial instanceof OpenPBRMaterial) { + if (babylonMaterial.coatDarkening) { + if (babylonMaterial.coatDarkeningTexture) { + additionalTextures.push(babylonMaterial.coatDarkeningTexture); + } + return additionalTextures; + } + } + + return []; + } + + // eslint-disable-next-line no-restricted-syntax + public postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise { + return new Promise((resolve) => { + let coatDarkeningFactor: Nullable = null; + let coatDarkeningTexture: Nullable = null; + if (babylonMaterial instanceof OpenPBRMaterial) { + coatDarkeningFactor = babylonMaterial.coatDarkening; + coatDarkeningTexture = babylonMaterial.coatDarkeningTexture; + } + if (coatDarkeningFactor === null || (coatDarkeningFactor === 1.0 && coatDarkeningTexture === null)) { + resolve(node); + return; + } + + this._wasUsed = true; + + // This material must have the clearcoat extension already before + // we can add the clearcoat darkening sub-extension + const parentExt = node.extensions ? node.extensions["KHR_materials_clearcoat"] : null; + if (!parentExt) { + resolve(node); + return; + } + + const coatDarkeningTextureInfo = this._exporter._materialExporter.getTextureInfo(coatDarkeningTexture); + + const coatDarkeningInfo: IEXTMaterialsClearcoatDarkening = { + clearcoatDarkeningFactor: coatDarkeningFactor, + clearcoatDarkeningTexture: coatDarkeningTextureInfo ?? undefined, + }; + + if (coatDarkeningInfo.clearcoatDarkeningTexture !== null) { + this._exporter._materialNeedsUVsSet.add(babylonMaterial); + } + + parentExt.extensions = parentExt.extensions || {}; + parentExt.extensions[NAME] = coatDarkeningInfo; + + resolve(node); + }); + } +} + +GLTFExporter.RegisterExtension(NAME, (exporter) => new EXT_materials_clearcoat_darkening(exporter)); diff --git a/packages/dev/serializers/src/glTF/2.0/Extensions/index.ts b/packages/dev/serializers/src/glTF/2.0/Extensions/index.ts index d2b5adfee31..78b8d361916 100644 --- a/packages/dev/serializers/src/glTF/2.0/Extensions/index.ts +++ b/packages/dev/serializers/src/glTF/2.0/Extensions/index.ts @@ -3,6 +3,7 @@ export * from "./KHR_draco_mesh_compression"; export * from "./KHR_lights_punctual"; export * from "./KHR_materials_anisotropy"; export * from "./KHR_materials_clearcoat"; +export * from "./EXT_materials_clearcoat_darkening"; export * from "./KHR_materials_diffuse_transmission"; export * from "./KHR_materials_dispersion"; export * from "./KHR_materials_emissive_strength"; diff --git a/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts b/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts index 6578b6e423b..f54807b2e8a 100644 --- a/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts +++ b/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts @@ -1068,6 +1068,18 @@ declare module BABYLON.GLTF2 { clearcoatRoughnessFactor?: number; clearcoatRoughnessTexture?: ITextureInfo; clearcoatNormalTexture?: IMaterialNormalTextureInfo; + /** + * Dictionary object with extension-specific objects + */ + extensions?: { + [key: string]: any; + }; + } + + /** @internal */ + interface IEXTMaterialsClearcoatDarkening { + clearcoatDarkeningFactor?: number; + clearcoatDarkeningTexture?: ITextureInfo; } /** @internal */ From ef48a7ccd3ef3d0a08447e75833e38d070672599 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 18 Aug 2025 13:58:39 -0700 Subject: [PATCH 44/45] Fix import in glTFExporter --- packages/dev/serializers/src/glTF/2.0/glTFExporter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts b/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts index 1374656c22e..38a9a70b754 100644 --- a/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts +++ b/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts @@ -80,7 +80,7 @@ import { Color3, Color4 } from "core/Maths/math.color"; import { TargetCamera } from "core/Cameras/targetCamera"; import { Epsilon } from "core/Maths/math.constants"; import { DataWriter } from "./dataWriter"; -import { OpenPBRMaterial } from "core/Materials"; +import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; class ExporterState { // Babylon indices array, start, count, offset, flip -> glTF accessor index From 048575931b6f371e6fb0452df9cee72d7c8d97c7 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Mon, 18 Aug 2025 14:27:11 -0700 Subject: [PATCH 45/45] Fix build errors --- .../components/actionTabs/tabs/propertyGridTabComponent.tsx | 2 +- packages/tools/sandbox/src/tools/environmentTools.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx index a2deb3ff06b..de6da686d63 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx @@ -118,7 +118,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"; +import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial"; export class PropertyGridTabComponent extends PaneComponent { private _timerIntervalId: number; diff --git a/packages/tools/sandbox/src/tools/environmentTools.ts b/packages/tools/sandbox/src/tools/environmentTools.ts index ef2d57e0407..e1bc486f171 100644 --- a/packages/tools/sandbox/src/tools/environmentTools.ts +++ b/packages/tools/sandbox/src/tools/environmentTools.ts @@ -7,7 +7,6 @@ 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 = ""; @@ -57,7 +56,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 | OpenPBRMaterial; + const material = currentScene.materials[i] as StandardMaterial | PBRMaterial; if (material.name === "skyBox") { const reflectionTexture = material.reflectionTexture; if (reflectionTexture && reflectionTexture.coordinatesMode === Texture.SKYBOX_MODE) {

-g@pW-juJV?V6IsCnYs#V6?A7MXuv?Upns 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 Z0dQ^pOnLX$NCIA(nv#}ct-NLEe*kPH?jryI diff --git a/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-Weight.png b/packages/tools/tests/test/visualization/ReferenceImages/OpenPBR-IBL-Specular-IOR-vs-Coat-Weight.png index 2179c39263ab39cfae89412e708e2e38ffd74602..a58485a2cf9033acdb61dc2a2a848ba22e126317 100644 GIT binary patch literal 111329 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 z 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%0DvLAT4Tfr8Kb@kPAMI0gl~Ht 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