@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
JavaScript
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,