UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

1,235 lines (1,233 loc) 103 kB
import { __decorate } from "../../tslib.es6.js"; /* eslint-disable @typescript-eslint/naming-convention */ import { serializeAsImageProcessingConfiguration, expandToProperty } from "../../Misc/decorators.js"; import { Logger } from "../../Misc/logger.js"; import { SmartArray } from "../../Misc/smartArray.js"; import { GetEnvironmentBRDFTexture } from "../../Misc/brdfTextureTools.js"; import { Scene } from "../../scene.js"; import { Vector4 } from "../../Maths/math.vector.js"; import { VertexBuffer } from "../../Buffers/buffer.js"; import { PBRBRDFConfiguration } from "./pbrBRDFConfiguration.js"; import { PrePassConfiguration } from "../prePassConfiguration.js"; import { Color3, TmpColors } from "../../Maths/math.color.js"; import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration.js"; import { Material } from "../../Materials/material.js"; import { MaterialDefines } from "../../Materials/materialDefines.js"; import { PushMaterial } from "../../Materials/pushMaterial.js"; import { Texture } from "../../Materials/Textures/texture.js"; import { MaterialFlags } from "../materialFlags.js"; import "../../Materials/Textures/baseTexture.polynomial.js"; import { EffectFallbacks } from "../effectFallbacks.js"; import { PBRClearCoatConfiguration } from "./pbrClearCoatConfiguration.js"; import { PBRIridescenceConfiguration } from "./pbrIridescenceConfiguration.js"; import { PBRAnisotropicConfiguration } from "./pbrAnisotropicConfiguration.js"; import { PBRSheenConfiguration } from "./pbrSheenConfiguration.js"; import { PBRSubSurfaceConfiguration } from "./pbrSubSurfaceConfiguration.js"; import { DetailMapConfiguration } from "../material.detailMapConfiguration.js"; import { addClipPlaneUniforms, bindClipPlane } from "../clipPlaneMaterialHelper.js"; import { BindBonesParameters, BindFogParameters, BindLights, BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareAttributesForMorphTargets, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, PrepareUniformsAndSamplersList, } from "../materialHelper.functions.js"; import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering.js"; const onCreatedEffectParameters = { effect: null, subMesh: null }; /** * Manages the defines for the PBR Material. * @internal */ export class PBRMaterialDefines extends MaterialDefines { /** * Initializes the PBR Material defines. * @param externalProperties The external properties */ constructor(externalProperties) { super(externalProperties); this.PBR = true; this.NUM_SAMPLES = "0"; this.REALTIME_FILTERING = false; this.IBL_CDF_FILTERING = false; this.MAINUV1 = false; this.MAINUV2 = false; this.MAINUV3 = false; this.MAINUV4 = false; this.MAINUV5 = false; this.MAINUV6 = false; this.UV1 = false; this.UV2 = false; this.UV3 = false; this.UV4 = false; this.UV5 = false; this.UV6 = false; this.ALBEDO = false; this.GAMMAALBEDO = false; this.ALBEDODIRECTUV = 0; this.VERTEXCOLOR = false; this.BASEWEIGHT = false; this.BASEWEIGHTDIRECTUV = 0; this.BAKED_VERTEX_ANIMATION_TEXTURE = false; this.AMBIENT = false; this.AMBIENTDIRECTUV = 0; this.AMBIENTINGRAYSCALE = false; this.OPACITY = false; this.VERTEXALPHA = false; this.OPACITYDIRECTUV = 0; this.OPACITYRGB = false; this.ALPHATEST = false; this.DEPTHPREPASS = false; this.ALPHABLEND = false; this.ALPHAFROMALBEDO = false; this.ALPHATESTVALUE = "0.5"; this.SPECULAROVERALPHA = false; this.RADIANCEOVERALPHA = false; this.ALPHAFRESNEL = false; this.LINEARALPHAFRESNEL = false; this.PREMULTIPLYALPHA = false; this.EMISSIVE = false; this.EMISSIVEDIRECTUV = 0; this.GAMMAEMISSIVE = false; this.REFLECTIVITY = false; this.REFLECTIVITY_GAMMA = false; this.REFLECTIVITYDIRECTUV = 0; this.SPECULARTERM = false; this.MICROSURFACEFROMREFLECTIVITYMAP = false; this.MICROSURFACEAUTOMATIC = false; this.LODBASEDMICROSFURACE = false; this.MICROSURFACEMAP = false; this.MICROSURFACEMAPDIRECTUV = 0; this.METALLICWORKFLOW = false; this.ROUGHNESSSTOREINMETALMAPALPHA = false; this.ROUGHNESSSTOREINMETALMAPGREEN = false; this.METALLNESSSTOREINMETALMAPBLUE = false; this.AOSTOREINMETALMAPRED = false; this.METALLIC_REFLECTANCE = false; this.METALLIC_REFLECTANCE_GAMMA = false; this.METALLIC_REFLECTANCEDIRECTUV = 0; this.METALLIC_REFLECTANCE_USE_ALPHA_ONLY = false; this.REFLECTANCE = false; this.REFLECTANCE_GAMMA = false; this.REFLECTANCEDIRECTUV = 0; this.ENVIRONMENTBRDF = false; this.ENVIRONMENTBRDF_RGBD = false; this.NORMAL = false; this.TANGENT = false; this.BUMP = false; this.BUMPDIRECTUV = 0; this.OBJECTSPACE_NORMALMAP = false; this.PARALLAX = false; this.PARALLAX_RHS = false; this.PARALLAXOCCLUSION = false; this.NORMALXYSCALE = true; this.LIGHTMAP = false; this.LIGHTMAPDIRECTUV = 0; this.USELIGHTMAPASSHADOWMAP = false; this.GAMMALIGHTMAP = false; this.RGBDLIGHTMAP = false; this.REFLECTION = false; this.REFLECTIONMAP_3D = false; this.REFLECTIONMAP_SPHERICAL = false; this.REFLECTIONMAP_PLANAR = false; this.REFLECTIONMAP_CUBIC = false; this.USE_LOCAL_REFLECTIONMAP_CUBIC = false; this.REFLECTIONMAP_PROJECTION = false; this.REFLECTIONMAP_SKYBOX = false; this.REFLECTIONMAP_EXPLICIT = false; this.REFLECTIONMAP_EQUIRECTANGULAR = false; this.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; this.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; this.INVERTCUBICMAP = false; this.USESPHERICALFROMREFLECTIONMAP = false; this.USEIRRADIANCEMAP = false; this.USESPHERICALINVERTEX = false; this.REFLECTIONMAP_OPPOSITEZ = false; this.LODINREFLECTIONALPHA = false; this.GAMMAREFLECTION = false; this.RGBDREFLECTION = false; this.LINEARSPECULARREFLECTION = false; this.RADIANCEOCCLUSION = false; this.HORIZONOCCLUSION = false; this.INSTANCES = false; this.THIN_INSTANCES = false; this.INSTANCESCOLOR = false; this.PREPASS = false; this.PREPASS_COLOR = false; this.PREPASS_COLOR_INDEX = -1; this.PREPASS_IRRADIANCE = false; this.PREPASS_IRRADIANCE_INDEX = -1; this.PREPASS_ALBEDO = false; this.PREPASS_ALBEDO_INDEX = -1; this.PREPASS_ALBEDO_SQRT = false; this.PREPASS_ALBEDO_SQRT_INDEX = -1; this.PREPASS_DEPTH = false; this.PREPASS_DEPTH_INDEX = -1; this.PREPASS_SCREENSPACE_DEPTH = false; this.PREPASS_SCREENSPACE_DEPTH_INDEX = -1; this.PREPASS_NORMAL = false; this.PREPASS_NORMAL_INDEX = -1; this.PREPASS_NORMAL_WORLDSPACE = false; this.PREPASS_WORLD_NORMAL = false; this.PREPASS_WORLD_NORMAL_INDEX = -1; this.PREPASS_POSITION = false; this.PREPASS_POSITION_INDEX = -1; this.PREPASS_LOCAL_POSITION = false; this.PREPASS_LOCAL_POSITION_INDEX = -1; this.PREPASS_VELOCITY = false; this.PREPASS_VELOCITY_INDEX = -1; this.PREPASS_VELOCITY_LINEAR = false; this.PREPASS_VELOCITY_LINEAR_INDEX = -1; this.PREPASS_REFLECTIVITY = false; this.PREPASS_REFLECTIVITY_INDEX = -1; this.SCENE_MRT_COUNT = 0; this.NUM_BONE_INFLUENCERS = 0; this.BonesPerMesh = 0; this.BONETEXTURE = false; this.BONES_VELOCITY_ENABLED = false; this.NONUNIFORMSCALING = false; this.MORPHTARGETS = false; this.MORPHTARGETS_POSITION = false; this.MORPHTARGETS_NORMAL = false; this.MORPHTARGETS_TANGENT = false; this.MORPHTARGETS_UV = false; this.MORPHTARGETS_UV2 = false; this.MORPHTARGETS_COLOR = false; this.MORPHTARGETTEXTURE_HASPOSITIONS = false; this.MORPHTARGETTEXTURE_HASNORMALS = false; this.MORPHTARGETTEXTURE_HASTANGENTS = false; this.MORPHTARGETTEXTURE_HASUVS = false; this.MORPHTARGETTEXTURE_HASUV2S = false; this.MORPHTARGETTEXTURE_HASCOLORS = false; this.NUM_MORPH_INFLUENCERS = 0; this.MORPHTARGETS_TEXTURE = false; this.IMAGEPROCESSING = false; this.VIGNETTE = false; this.VIGNETTEBLENDMODEMULTIPLY = false; this.VIGNETTEBLENDMODEOPAQUE = false; this.TONEMAPPING = 0; this.CONTRAST = false; this.COLORCURVES = false; this.COLORGRADING = false; this.COLORGRADING3D = false; this.SAMPLER3DGREENDEPTH = false; this.SAMPLER3DBGRMAP = false; this.DITHER = false; this.IMAGEPROCESSINGPOSTPROCESS = false; this.SKIPFINALCOLORCLAMP = false; this.EXPOSURE = false; this.MULTIVIEW = false; this.ORDER_INDEPENDENT_TRANSPARENCY = false; this.ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false; this.USEPHYSICALLIGHTFALLOFF = false; this.USEGLTFLIGHTFALLOFF = false; this.TWOSIDEDLIGHTING = false; this.MIRRORED = false; this.SHADOWFLOAT = false; this.CLIPPLANE = false; this.CLIPPLANE2 = false; this.CLIPPLANE3 = false; this.CLIPPLANE4 = false; this.CLIPPLANE5 = false; this.CLIPPLANE6 = false; this.POINTSIZE = false; this.FOG = false; this.LOGARITHMICDEPTH = false; this.CAMERA_ORTHOGRAPHIC = false; this.CAMERA_PERSPECTIVE = false; this.AREALIGHTSUPPORTED = true; this.FORCENORMALFORWARD = false; this.SPECULARAA = false; this.UNLIT = false; this.DECAL_AFTER_DETAIL = false; this.DEBUGMODE = 0; this.rebuild(); } /** * Resets the PBR Material defines. */ reset() { super.reset(); this.ALPHATESTVALUE = "0.5"; this.PBR = true; this.NORMALXYSCALE = true; } } /** * The Physically based material base class 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 * @see [WebGL](https://playground.babylonjs.com/#CGHTSM#1) * @see [WebGPU](https://playground.babylonjs.com/#CGHTSM#2) */ export class PBRBaseMaterial extends PushMaterial { /** * Enables realtime filtering on the texture. */ get realTimeFiltering() { return this._realTimeFiltering; } set realTimeFiltering(b) { this._realTimeFiltering = b; this.markAsDirty(1); } /** * Quality switch for realtime filtering */ get realTimeFilteringQuality() { return this._realTimeFilteringQuality; } set realTimeFilteringQuality(n) { this._realTimeFilteringQuality = n; this.markAsDirty(1); } /** * Can this material render to several textures at once */ get canRenderToMRT() { return true; } /** * Attaches a new image processing configuration to the PBR Material. * @param configuration */ _attachImageProcessingConfiguration(configuration) { 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(); }); } } /** * Instantiates a new PBRMaterial 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, scene, forceGLSL = false) { super(name, scene, undefined, forceGLSL || PBRBaseMaterial.ForceGLSL); /** * Intensity of the direct lights e.g. the four lights available in your scene. * This impacts both the direct diffuse and specular highlights. * @internal */ this._directIntensity = 1.0; /** * Intensity of the emissive part of the material. * This helps controlling the emissive effect without modifying the emissive color. * @internal */ this._emissiveIntensity = 1.0; /** * Intensity of the environment e.g. how much the environment will light the object * either through harmonics for rough material or through the reflection for shiny ones. * @internal */ this._environmentIntensity = 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 */ this._specularIntensity = 1.0; /** * This stores the direct, emissive, environment, and specular light intensities into a Vector4. */ this._lightingInfos = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, this._specularIntensity); /** * Debug Control allowing disabling the bump map on this material. * @internal */ this._disableBumpMap = false; /** * AKA Diffuse Texture in standard nomenclature. * @internal */ this._albedoTexture = null; /** * OpenPBR Base Weight (multiplier to the diffuse and metal lobes). * @internal */ this._baseWeightTexture = null; /** * AKA Occlusion Texture in other nomenclature. * @internal */ this._ambientTexture = null; /** * AKA Occlusion Texture Intensity in other nomenclature. * @internal */ this._ambientTextureStrength = 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 */ this._ambientTextureImpactOnAnalyticalLights = PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS; /** * Stores the alpha values in a texture. * @internal */ this._opacityTexture = null; /** * Stores the reflection values in a texture. * @internal */ this._reflectionTexture = null; /** * Stores the emissive values in a texture. * @internal */ this._emissiveTexture = null; /** * AKA Specular texture in other nomenclature. * @internal */ this._reflectivityTexture = null; /** * Used to switch from specular/glossiness to metallic/roughness workflow. * @internal */ this._metallicTexture = null; /** * Specifies the metallic scalar of the metallic/roughness workflow. * Can also be used to scale the metalness values of the metallic texture. * @internal */ this._metallic = null; /** * Specifies the roughness scalar of the metallic/roughness workflow. * Can also be used to scale the roughness values of the metallic texture. * @internal */ this._roughness = 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 */ this._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 */ this._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 */ this._useOnlyMetallicFromMetallicReflectanceTexture = false; /** * Defines to store metallicReflectanceColor in RGB and metallicF0Factor in A * This is multiply against the scalar values defined in the material. * @internal */ this._metallicReflectanceTexture = 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 */ this._reflectanceTexture = 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 */ this._microSurfaceTexture = null; /** * Stores surface normal data used to displace a mesh in a texture. * @internal */ this._bumpTexture = null; /** * Stores the pre-calculated light information of a mesh in a texture. * @internal */ this._lightmapTexture = null; /** * The color of a material in ambient lighting. * @internal */ this._ambientColor = new Color3(0, 0, 0); /** * AKA Diffuse Color in other nomenclature. * @internal */ this._albedoColor = new Color3(1, 1, 1); /** * OpenPBR Base Weight (multiplier to the diffuse and metal lobes). * @internal */ this._baseWeight = 1; /** * AKA Specular Color in other nomenclature. * @internal */ this._reflectivityColor = new Color3(1, 1, 1); /** * The color applied when light is reflected from a material. * @internal */ this._reflectionColor = new Color3(1, 1, 1); /** * The color applied when light is emitted from a material. * @internal */ this._emissiveColor = new Color3(0, 0, 0); /** * AKA Glossiness in other nomenclature. * @internal */ this._microSurface = 0.9; /** * Specifies that the material will use the light map as a show map. * @internal */ this._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 */ this._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 */ this._useRadianceOcclusion = true; /** * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending. * @internal */ this._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 */ this._useSpecularOverAlpha = true; /** * Specifies if the reflectivity texture contains the glossiness information in its alpha channel. * @internal */ this._useMicroSurfaceFromReflectivityMapAlpha = false; /** * Specifies if the metallic texture contains the roughness information in its alpha channel. * @internal */ this._useRoughnessFromMetallicTextureAlpha = true; /** * Specifies if the metallic texture contains the roughness information in its green channel. * @internal */ this._useRoughnessFromMetallicTextureGreen = false; /** * Specifies if the metallic texture contains the metallness information in its blue channel. * @internal */ this._useMetallnessFromMetallicTextureBlue = false; /** * Specifies if the metallic texture contains the ambient occlusion information in its red channel. * @internal */ this._useAmbientOcclusionFromMetallicTextureRed = false; /** * Specifies if the ambient texture contains the ambient occlusion information in its red channel only. * @internal */ this._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 */ this._useAutoMicroSurfaceFromReflectivityMap = false; /** * Defines the falloff type used in this material. * It by default is Physical. * @internal */ this._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 */ this._useRadianceOverAlpha = true; /** * Allows using an object space normal map (instead of tangent space). * @internal */ this._useObjectSpaceNormalMap = false; /** * Allows using the bump map in parallax mode. * @internal */ this._useParallax = false; /** * Allows using the bump map in parallax occlusion mode. * @internal */ this._useParallaxOcclusion = false; /** * Controls the scale bias of the parallax mode. * @internal */ this._parallaxScaleBias = 0.05; /** * If sets to true, disables all the lights affecting the material. * @internal */ this._disableLighting = false; /** * Number of Simultaneous lights allowed on the material. * @internal */ this._maxSimultaneousLights = 4; /** * If sets to true, x component of normal map value will be inverted (x = 1.0 - x). * @internal */ this._invertNormalMapX = false; /** * If sets to true, y component of normal map value will be inverted (y = 1.0 - y). * @internal */ this._invertNormalMapY = false; /** * If sets to true and backfaceCulling is false, normals will be flipped on the backside. * @internal */ this._twoSidedLighting = false; /** * Defines the alpha limits in alpha test mode. * @internal */ this._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 */ this._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 */ this._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 */ this._environmentBRDFTexture = null; /** * Force the shader to compute irradiance in the fragment shader in order to take bump in account. * @internal */ this._forceIrradianceInFragment = false; this._realTimeFiltering = false; this._realTimeFilteringQuality = 8; /** * Force normal to face away from face. * @internal */ this._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 */ this._enableSpecularAntiAliasing = false; /** * Keep track of the image processing observer to allow dispose and replace. */ this._imageProcessingObserver = null; /** * Stores the available render targets. */ this._renderTargets = new SmartArray(16); /** * Sets the global ambient color for the material used in lighting calculations. */ this._globalAmbientColor = new Color3(0, 0, 0); /** * If set to true, no lighting calculations will be applied. */ this._unlit = false; /** * If sets to true, the decal map will be applied after the detail map. Else, it is applied before (default: false) */ this._applyDecalMapAfterDetailMap = false; this._debugMode = 0; this._shadersLoaded = false; this._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. */ this.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 */ this.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. */ this.debugFactor = 1; this._cacheHasRenderTargetTextures = false; this.brdf = new PBRBRDFConfiguration(this); this.clearCoat = new PBRClearCoatConfiguration(this); this.iridescence = new PBRIridescenceConfiguration(this); this.anisotropy = new PBRAnisotropicConfiguration(this); this.sheen = new PBRSheenConfiguration(this); this.subSurface = new PBRSubSurfaceConfiguration(this); this.detailMap = new DetailMapConfiguration(this); // Setup the default processing configuration to the scene. this._attachImageProcessingConfiguration(null); this.getRenderTargetTextures = () => { 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(); } /** * Gets a boolean indicating that current material needs to register RTT */ get hasRenderTargetTextures() { if (MaterialFlags.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { return true; } return this._cacheHasRenderTargetTextures; } /** * Can this material render to prepass */ get isPrePassCapable() { return !this.disableDepthWrite; } /** * @returns the name of the material class. */ getClassName() { return "PBRBaseMaterial"; } /** * Returns true if alpha blending should be disabled. */ get _disableAlphaBlending() { return (this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_OPAQUE || this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST || this.subSurface?.disableAlphaBlending); } /** * @returns whether or not this material should be rendered in alpha blend mode. */ needAlphaBlending() { 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. */ needAlphaTesting() { if (this._hasTransparencyMode) { return this._transparencyModeIsTest; } if (this.subSurface?.disableAlphaBlending) { return false; } 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. */ _shouldUseAlphaFromAlbedoTexture() { 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. */ _hasAlphaChannel() { return (this._albedoTexture != null && this._albedoTexture.hasAlpha) || this._opacityTexture != null; } /** * @returns the texture used for the alpha test. */ getAlphaTestTexture() { return this._albedoTexture; } /** * 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. */ isReadyForSubMesh(mesh, subMesh, useInstances) { 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(4 /* MaterialPluginEvent.GetDefineNames */, this._eventInfo); subMesh.materialDefines = new PBRMaterialDefines(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._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()) { 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("PBRMaterial: 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; } /** * Specifies if the material uses metallic roughness workflow. * @returns boolean specifying if the material uses metallic roughness workflow. */ isMetallicWorkflow() { if (this._metallic != null || this._roughness != null || this._metallicTexture) { return true; } return false; } _prepareEffect(mesh, defines, onCompiled = null, onError = null, useInstances = null, useClipPlane = null, useThinInstances) { this._prepareDefines(mesh, defines, useInstances, useClipPlane, useThinInstances); if (!defines.isDirty) { return null; } defines.markAsProcessed(); const scene = this.getScene(); const engine = scene.getEngine(); // Fallbacks const fallbacks = new EffectFallbacks(); let fallbackRank = 0; if (defines.USESPHERICALINVERTEX) { fallbacks.addFallback(fallbackRank++, "USESPHERICALINVERTEX"); } if (defines.FOG) { fallbacks.addFallback(fallbackRank, "FOG"); } if (defines.SPECULARAA) { fallbacks.addFallback(fallbackRank, "SPECULARAA"); } if (defines.POINTSIZE) { fallbacks.addFallback(fallbackRank, "POINTSIZE"); } if (defines.LOGARITHMICDEPTH) { fallbacks.addFallback(fallbackRank, "LOGARITHMICDEPTH"); } if (defines.PARALLAX) { fallbacks.addFallback(fallbackRank, "PARALLAX"); } if (defines.PARALLAX_RHS) { fallbacks.addFallback(fallbackRank, "PARALLAX_RHS"); } if (defines.PARALLAXOCCLUSION) { fallbacks.addFallback(fallbackRank++, "PARALLAXOCCLUSION"); } if (defines.ENVIRONMENTBRDF) { fallbacks.addFallback(fallbackRank++, "ENVIRONMENTBRDF"); } if (defines.TANGENT) { fallbacks.addFallback(fallbackRank++, "TANGENT"); } if (defines.BUMP) { fallbacks.addFallback(fallbackRank++, "BUMP"); } fallbackRank = HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights, fallbackRank++); if (defines.SPECULARTERM) { fallbacks.addFallback(fallbackRank++, "SPECULARTERM"); } if (defines.USESPHERICALFROMREFLECTIONMAP) { fallbacks.addFallback(fallbackRank++, "USESPHERICALFROMREFLECTIONMAP"); } if (defines.USEIRRADIANCEMAP) { fallbacks.addFallback(fallbackRank++, "USEIRRADIANCEMAP"); } if (defines.LIGHTMAP) { fallbacks.addFallback(fallbackRank++, "LIGHTMAP"); } if (defines.NORMAL) { fallbacks.addFallback(fallbackRank++, "NORMAL"); } if (defines.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 <= 6; ++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 = "pbr"; const uniforms = [ "world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "baseWeight", "vReflectivityColor", "vMetallicReflectanceFactors", "vEmissiveColor", "visibility", "vReflectionColor", "vFogInfos", "vFogColor", "pointSize", "vAlbedoInfos", "vBaseWeightInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", "vReflectionFilteringInfo", "vMetallicReflectanceInfos", "vReflectanceInfos", "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "mBones", "albedoMatrix", "baseWeightMatrix", "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", "vTangentSpaceParams", "boneTextureWidth", "vDebugMode", "morphTargetTextureInfo", "morphTargetTextureIndices", ]; const samplers = [ "albedoSampler", "baseWeightSampler", "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(128 /* 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 = {}; 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,