@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,081 lines (1,079 loc) • 117 kB
JavaScript
import { __decorate } from "../../tslib.es6.js";
/* eslint-disable @typescript-eslint/naming-convention */
import { serialize, expandToProperty, addAccessorsForMaterialProperty } from "../../Misc/decorators.js";
import { GetEnvironmentBRDFTexture, GetEnvironmentFuzzBRDFTexture } from "../../Misc/brdfTextureTools.js";
import { Color3 } from "../../Maths/math.color.js";
import { ImageProcessingConfiguration } from "../imageProcessingConfiguration.js";
import { Texture } from "../Textures/texture.js";
import { RegisterClass } from "../../Misc/typeStore.js";
import { Material } from "../material.js";
import { SerializationHelper } from "../../Misc/decorators.serialization.js";
import { MaterialDefines } from "../materialDefines.js";
import { ImageProcessingDefinesMixin } from "../imageProcessingConfiguration.defines.js";
import { EffectFallbacks } from "../effectFallbacks.js";
import { AddClipPlaneUniforms, BindClipPlane } from "../clipPlaneMaterialHelper.js";
import { PrepareVertexPullingUniforms, BindVertexPullingUniforms } from "../vertexPullingHelper.functions.js";
import { BindBonesParameters, BindFogParameters, BindLights, BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, BindIBLParameters, BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareAttributesForMorphTargets, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, PrepareUniformsAndSamplersList, PrepareUniformsAndSamplersForIBL, PrepareUniformLayoutForIBL, } from "../materialHelper.functions.js";
import { VertexBuffer } from "../../Buffers/buffer.js";
import { MaterialHelperGeometryRendering } from "../materialHelper.geometryrendering.js";
import { PrePassConfiguration } from "../prePassConfiguration.js";
import { MaterialFlags } from "../materialFlags.js";
import { Logger } from "../../Misc/logger.js";
import { UVDefinesMixin } from "../uv.defines.js";
import { Vector2, Vector4, TmpVectors } from "../../Maths/math.vector.js";
import { ImageProcessingMixin } from "../imageProcessing.js";
import { PushMaterial } from "../pushMaterial.js";
import { SmartArray } from "../../Misc/smartArray.js";
import { Tools } from "../../Misc/tools.js";
const onCreatedEffectParameters = { effect: null, subMesh: null };
class Uniform {
populateVectorFromLinkedProperties(vector) {
const destinationSize = vector.dimension[0];
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);
}
constructor(name, componentNum) {
this.linkedProperties = {};
this.name = name;
this.numComponents = componentNum;
}
}
Uniform._tmpArray = [0, 0, 0, 0];
/**
* Defines a property for the OpenPBRMaterial.
*/
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 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, defaultValue, targetUniformName, targetUniformComponentNum, targetUniformComponentOffset = 0) {
// 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.
*/
this.targetUniformComponentNum = 4; // Default to vec4
this.targetUniformComponentOffset = 0;
this.name = name;
this.targetUniformName = targetUniformName;
this.defaultValue = defaultValue;
this.value = defaultValue;
this.targetUniformComponentNum = targetUniformComponentNum;
this.targetUniformComponentOffset = targetUniformComponentOffset;
}
/**
* Returns the number of components of the property based on its default value type.
*/
get numComponents() {
if (typeof this.defaultValue === "number") {
return 1;
}
return this.defaultValue.dimension[0];
}
}
class 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
*/
get samplerName() {
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
*/
get samplerInfoName() {
return "v" + this.samplerPrefix.charAt(0).toUpperCase() + this.samplerPrefix.slice(1) + "Infos";
}
/**
* The name of the matrix used for this sampler in the shader.
* If this naming changes, we'll also need to change:
* - materialHelper.functions.BindTextureMatrix
* - samplerVertexImplementation.fx
* - openpbr.fragment.fx
*/
get samplerMatrixName() {
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, samplerPrefix, textureDefine) {
this.value = null; // Texture value, default to null
this.samplerPrefix = ""; // The name of the sampler in the shader
this.textureDefine = ""; // The define used in the shader for this sampler
this.name = name;
this.samplerPrefix = samplerPrefix;
this.textureDefine = textureDefine;
}
}
class OpenPBRMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) {
}
/**
* Manages the defines for the PBR Material.
* @internal
*/
export class OpenPBRMaterialDefines extends ImageProcessingDefinesMixin(OpenPBRMaterialDefinesBase) {
/**
* Initializes the PBR Material defines.
* @param externalProperties The external properties
*/
constructor(externalProperties) {
super(externalProperties);
this.NUM_SAMPLES = "0";
this.REALTIME_FILTERING = false;
this.IBL_CDF_FILTERING = false;
this.VERTEXCOLOR = false;
this.BAKED_VERTEX_ANIMATION_TEXTURE = false;
this.VERTEXALPHA = false;
this.ALPHATEST = false;
this.DEPTHPREPASS = false;
this.ALPHABLEND = false;
this.ALPHA_FROM_BASE_COLOR_TEXTURE = false;
this.ALPHATESTVALUE = "0.5";
this.PREMULTIPLYALPHA = false;
this.REFLECTIVITY_GAMMA = false;
this.REFLECTIVITYDIRECTUV = 0;
this.SPECULARTERM = false;
this.LODBASEDMICROSFURACE = true;
this.SPECULAR_ROUGHNESS_FROM_METALNESS_TEXTURE_GREEN = false;
this.BASE_METALNESS_FROM_METALNESS_TEXTURE_BLUE = false;
this.AOSTOREINMETALMAPRED = false;
this.SPECULAR_WEIGHT_IN_ALPHA = false;
this.SPECULAR_WEIGHT_FROM_SPECULAR_COLOR_TEXTURE = false;
this.SPECULAR_ROUGHNESS_ANISOTROPY_FROM_TANGENT_TEXTURE = false;
this.COAT_ROUGHNESS_FROM_GREEN_CHANNEL = false;
this.COAT_ROUGHNESS_ANISOTROPY_FROM_TANGENT_TEXTURE = false;
this.USE_GLTF_STYLE_ANISOTROPY = false;
this.THIN_FILM_THICKNESS_FROM_THIN_FILM_TEXTURE = false;
this.FUZZ_ROUGHNESS_FROM_TEXTURE_ALPHA = false;
this.GEOMETRY_THICKNESS_FROM_GREEN_CHANNEL = false;
this.ENVIRONMENTBRDF = false;
this.ENVIRONMENTBRDF_RGBD = false;
this.FUZZENVIRONMENTBRDF = false;
this.NORMAL = false;
this.TANGENT = false;
this.OBJECTSPACE_NORMALMAP = false;
this.PARALLAX = false;
this.PARALLAX_RHS = false;
this.PARALLAXOCCLUSION = false;
this.NORMALXYSCALE = true;
/**
* Enables anisotropic logic. Still needed because it's used in pbrHelperFunctions
*/
this.ANISOTROPIC = false;
/**
* Tells the shader to use OpenPBR's anisotropic roughness remapping
*/
this.ANISOTROPIC_OPENPBR = true;
/**
* Tells the shader to apply anisotropy to the base layer
*/
this.ANISOTROPIC_BASE = false;
/**
* Tells the shader to apply anisotropy to the coat layer
*/
this.ANISOTROPIC_COAT = false;
/**
* Number of samples to use for the fuzz IBL lighting calculations
*/
this.FUZZ_IBL_SAMPLES = 6;
/**
* Tells the shader to enable the fuzz layer
*/
this.FUZZ = false;
/**
* Tells the shader to enable the thin film layer
*/
this.THIN_FILM = false;
/**
* Tells the shader to enable the legacy iridescence code
* Iridescence is the name of thin film interference in the PBR material.
*/
this.IRIDESCENCE = false;
/**
* Tells the shader to enable dispersion in refraction
*/
this.DISPERSION = false;
/**
* Enables subsurface scattering
*/
this.SCATTERING = false;
/**
* Refraction of the 2D background texture. Might include the rest of the scene or just the background.
*/
this.REFRACTED_BACKGROUND = false;
/**
* Refraction of direct lights.
*/
this.REFRACTED_LIGHTS = false;
/**
* Refraction of the environment texture (IBL).
*/
this.REFRACTED_ENVIRONMENT = false;
this.REFRACTED_ENVIRONMENT_OPPOSITEZ = false;
this.REFRACTED_ENVIRONMENT_LOCAL_CUBE = 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.USE_IRRADIANCE_DOMINANT_DIRECTION = false;
this.USESPHERICALINVERTEX = false;
this.REFLECTIONMAP_OPPOSITEZ = false;
this.LODINREFLECTIONALPHA = false;
this.GAMMAREFLECTION = false;
this.RGBDREFLECTION = 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_NORMALIZED_VIEW_DEPTH = false;
this.PREPASS_NORMALIZED_VIEW_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.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.USE_VERTEX_PULLING = false;
this.VERTEX_PULLING_USE_INDEX_BUFFER = false;
this.VERTEX_PULLING_INDEX_BUFFER_32BITS = false;
this.RIGHT_HANDED = false;
this.CLUSTLIGHT_SLICES = 0;
this.CLUSTLIGHT_BATCH = 0;
// BRDF defines
this.BRDF_V_HEIGHT_CORRELATED = true;
this.MS_BRDF_ENERGY_CONSERVATION = true;
this.SPHERICAL_HARMONICS = true;
this.SPECULAR_GLOSSINESS_ENERGY_CONSERVATION = true;
this.MIX_IBL_RADIANCE_WITH_IRRADIANCE = true;
this.LEGACY_SPECULAR_ENERGY_CONSERVATION = false;
this.BASE_DIFFUSE_MODEL = 0;
this.DIELECTRIC_SPECULAR_MODEL = 1;
this.CONDUCTOR_SPECULAR_MODEL = 1;
this.rebuild();
}
/**
* Resets the PBR Material defines.
*/
reset() {
super.reset();
this.ALPHATESTVALUE = "0.5";
this.NORMALXYSCALE = true;
}
}
class OpenPBRMaterialBase extends ImageProcessingMixin(PushMaterial) {
}
/**
* A Physically based material that follows the specification of OpenPBR.
*
* For more information, please refer to the documentation :
* https://academysoftwarefoundation.github.io/OpenPBR/index.html
*/
export class OpenPBRMaterial extends OpenPBRMaterialBase {
/**
* Defines the angle of the tangent of the material's geometry. Used only for anisotropic reflections.
* See OpenPBR's specs for geometry_tangent
*/
get geometryTangentAngle() {
return Math.atan2(this.geometryTangent.y, this.geometryTangent.x);
}
set geometryTangentAngle(value) {
this.geometryTangent = new Vector2(Math.cos(value), Math.sin(value));
}
/**
* Defines the angle of the tangent of the material's coat layer.
*/
get geometryCoatTangentAngle() {
return Math.atan2(this.geometryCoatTangent.y, this.geometryCoatTangent.x);
}
/**
* Defines the angle of the tangent of the material's coat layer.
*/
set geometryCoatTangentAngle(value) {
this.geometryCoatTangent = new Vector2(Math.cos(value), Math.sin(value));
}
/**
* 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.
*/
get usePhysicalLightFalloff() {
return this._lightFalloff === Material.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.
*/
set usePhysicalLightFalloff(value) {
if (value !== this.usePhysicalLightFalloff) {
// Ensure the effect will be rebuilt.
this._markAllSubMeshesAsTexturesDirty();
if (value) {
this._lightFalloff = Material.LIGHTFALLOFF_PHYSICAL;
}
else {
this._lightFalloff = Material.LIGHTFALLOFF_STANDARD;
}
}
}
/**
* In order to support the falloff compatibility with gltf, a special mode has been added
* to reproduce the gltf light falloff.
*/
get useGLTFLightFalloff() {
return this._lightFalloff === Material.LIGHTFALLOFF_GLTF;
}
/**
* In order to support the falloff compatibility with gltf, a special mode has been added
* to reproduce the gltf light falloff.
*/
set useGLTFLightFalloff(value) {
if (value !== this.useGLTFLightFalloff) {
// Ensure the effect will be rebuilt.
this._markAllSubMeshesAsTexturesDirty();
if (value) {
this._lightFalloff = Material.LIGHTFALLOFF_GLTF;
}
else {
this._lightFalloff = Material.LIGHTFALLOFF_STANDARD;
}
}
}
/**
* Set the texture used for refraction of the background of transparent materials
* @internal
*/
get backgroundRefractionTexture() {
return this._backgroundRefractionTexture;
}
set backgroundRefractionTexture(texture) {
this._backgroundRefractionTexture = texture;
this._markAllSubMeshesAsTexturesDirty();
}
/**
* 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);
}
/**
* The number of samples used to compute the fuzz IBL lighting.
*/
get fuzzSampleNumber() {
return this._fuzzSampleNumber;
}
set fuzzSampleNumber(n) {
this._fuzzSampleNumber = n;
this.markAsDirty(1);
}
/**
* Can this material render to several textures at once
*/
get canRenderToMRT() {
return true;
}
/**
* Instantiates a new OpenPBRMaterial instance.
*
* @param name The material name
* @param scene The scene the material will be use in.
* @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false
*/
constructor(name, scene, forceGLSL = false) {
super(name, scene, undefined, forceGLSL || OpenPBRMaterial.ForceGLSL);
this._baseWeight = new Property("base_weight", 1, "vBaseWeight", 1);
this._baseWeightTexture = new Sampler("base_weight", "baseWeight", "BASE_WEIGHT");
this._baseColor = new Property("base_color", Color3.White(), "vBaseColor", 4);
this._baseColorTexture = new Sampler("base_color", "baseColor", "BASE_COLOR");
this._baseDiffuseRoughness = new Property("base_diffuse_roughness", 0, "vBaseDiffuseRoughness", 1);
this._baseDiffuseRoughnessTexture = new Sampler("base_diffuse_roughness", "baseDiffuseRoughness", "BASE_DIFFUSE_ROUGHNESS");
this._baseMetalness = new Property("base_metalness", 0, "vReflectanceInfo", 4, 0);
this._baseMetalnessTexture = new Sampler("base_metalness", "baseMetalness", "BASE_METALNESS");
this._specularWeight = new Property("specular_weight", 1, "vReflectanceInfo", 4, 3);
this._specularWeightTexture = new Sampler("specular_weight", "specularWeight", "SPECULAR_WEIGHT");
this._specularColor = new Property("specular_color", Color3.White(), "vSpecularColor", 4);
this._specularColorTexture = new Sampler("specular_color", "specularColor", "SPECULAR_COLOR");
this._specularRoughness = new Property("specular_roughness", 0.3, "vReflectanceInfo", 4, 1);
this._specularRoughnessTexture = new Sampler("specular_roughness", "specularRoughness", "SPECULAR_ROUGHNESS");
this._specularRoughnessAnisotropy = new Property("specular_roughness_anisotropy", 0, "vSpecularAnisotropy", 3, 2);
this._specularRoughnessAnisotropyTexture = new Sampler("specular_roughness_anisotropy", "specularRoughnessAnisotropy", "SPECULAR_ROUGHNESS_ANISOTROPY");
this._specularIor = new Property("specular_ior", 1.5, "vReflectanceInfo", 4, 2);
this._transmissionWeight = new Property("transmission_weight", 0.0, "vTransmissionWeight", 1);
this._transmissionWeightTexture = new Sampler("transmission_weight", "transmissionWeight", "TRANSMISSION_WEIGHT");
this._transmissionColor = new Property("transmission_color", Color3.White(), "vTransmissionColor", 3, 0);
this._transmissionColorTexture = new Sampler("transmission_color", "transmissionColor", "TRANSMISSION_COLOR");
this._transmissionDepth = new Property("transmission_depth", 0.0, "vTransmissionDepth", 1, 0);
this._transmissionDepthTexture = new Sampler("transmission_depth", "transmissionDepth", "TRANSMISSION_DEPTH");
this._transmissionScatter = new Property("transmission_scatter", Color3.Black(), "vTransmissionScatter", 3, 0);
this._transmissionScatterTexture = new Sampler("transmission_scatter", "transmissionScatter", "TRANSMISSION_SCATTER");
this._transmissionScatterAnisotropy = new Property("transmission_scatter_anisotropy", 0.0, "vTransmissionScatterAnisotropy", 1, 0);
this._transmissionDispersionScale = new Property("transmission_dispersion_scale", 0.0, "vTransmissionDispersionScale", 1, 0);
this._transmissionDispersionScaleTexture = new Sampler("transmission_dispersion_scale", "transmissionDispersionScale", "TRANSMISSION_DISPERSION_SCALE");
this._transmissionDispersionAbbeNumber = new Property("transmission_dispersion_abbe_number", 20.0, "vTransmissionDispersionAbbeNumber", 1, 0);
this._coatWeight = new Property("coat_weight", 0.0, "vCoatWeight", 1, 0);
this._coatWeightTexture = new Sampler("coat_weight", "coatWeight", "COAT_WEIGHT");
this._coatColor = new Property("coat_color", Color3.White(), "vCoatColor", 3, 0);
this._coatColorTexture = new Sampler("coat_color", "coatColor", "COAT_COLOR");
this._coatRoughness = new Property("coat_roughness", 0.0, "vCoatRoughness", 1, 0);
this._coatRoughnessTexture = new Sampler("coat_roughness", "coatRoughness", "COAT_ROUGHNESS");
this._coatRoughnessAnisotropy = new Property("coat_roughness_anisotropy", 0, "vCoatRoughnessAnisotropy", 1);
this._coatRoughnessAnisotropyTexture = new Sampler("coat_roughness_anisotropy", "coatRoughnessAnisotropy", "COAT_ROUGHNESS_ANISOTROPY");
this._coatIor = new Property("coat_ior", 1.5, "vCoatIor", 1, 0);
this._coatDarkening = new Property("coat_darkening", 1.0, "vCoatDarkening", 1, 0);
this._coatDarkeningTexture = new Sampler("coat_darkening", "coatDarkening", "COAT_DARKENING");
/**
* Specifies whether the coat roughness is taken from the
* same texture as the coat_weight.
*/
this.useCoatRoughnessFromWeightTexture = false;
this._fuzzWeight = new Property("fuzz_weight", 0.0, "vFuzzWeight", 1, 0);
this._fuzzWeightTexture = new Sampler("fuzz_weight", "fuzzWeight", "FUZZ_WEIGHT");
this._fuzzColor = new Property("fuzz_color", Color3.White(), "vFuzzColor", 3, 0);
this._fuzzColorTexture = new Sampler("fuzz_color", "fuzzColor", "FUZZ_COLOR");
this._fuzzRoughness = new Property("fuzz_roughness", 0.5, "vFuzzRoughness", 1, 0);
this._fuzzRoughnessTexture = new Sampler("fuzz_roughness", "fuzzRoughness", "FUZZ_ROUGHNESS");
this._geometryNormalTexture = new Sampler("geometry_normal", "geometryNormal", "GEOMETRY_NORMAL");
this._geometryTangent = new Property("geometry_tangent", new Vector2(1, 0), "vSpecularAnisotropy", 3, 0);
this._geometryTangentTexture = new Sampler("geometry_tangent", "geometryTangent", "GEOMETRY_TANGENT");
this._geometryCoatNormalTexture = new Sampler("geometry_coat_normal", "geometryCoatNormal", "GEOMETRY_COAT_NORMAL");
this._geometryCoatTangent = new Property("geometry_coat_tangent", new Vector2(1, 0), "vGeometryCoatTangent", 2, 0);
this._geometryCoatTangentTexture = new Sampler("geometry_coat_tangent", "geometryCoatTangent", "GEOMETRY_COAT_TANGENT");
this._geometryOpacity = new Property("geometry_opacity", 1.0, "vBaseColor", 4, 3);
this._geometryOpacityTexture = new Sampler("geometry_opacity", "geometryOpacity", "GEOMETRY_OPACITY");
this._geometryThickness = new Property("geometry_thickness", 0.0, "vGeometryThickness", 1, 0);
this._geometryThicknessTexture = new Sampler("geometry_thickness", "geometryThickness", "GEOMETRY_THICKNESS");
this._emissionLuminance = new Property("emission_luminance", 1.0, "vLightingIntensity", 4, 1);
this._emissionColor = new Property("emission_color", Color3.Black(), "vEmissionColor", 3);
this._emissionColorTexture = new Sampler("emission_color", "emissionColor", "EMISSION_COLOR");
this._thinFilmWeight = new Property("thin_film_weight", 0.0, "vThinFilmWeight", 1, 0);
this._thinFilmWeightTexture = new Sampler("thin_film_weight", "thinFilmWeight", "THIN_FILM_WEIGHT");
this._thinFilmThickness = new Property("thin_film_thickness", 0.5, "vThinFilmThickness", 2, 0);
this._thinFilmThicknessMin = new Property("thin_film_thickness_min", 0.0, "vThinFilmThickness", 2, 1);
this._thinFilmThicknessTexture = new Sampler("thin_film_thickness", "thinFilmThickness", "THIN_FILM_THICKNESS");
this._thinFilmIor = new Property("thin_film_ior", 1.4, "vThinFilmIor", 1, 0);
this._ambientOcclusionTexture = new Sampler("ambient_occlusion", "ambientOcclusion", "AMBIENT_OCCLUSION");
this._uniformsList = {};
this._samplersList = {};
this._samplerDefines = {};
/**
* Intensity of the direct lights e.g. the four lights available in your scene.
* This impacts both the direct diffuse and specular highlights.
*/
this.directIntensity = 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.
*/
this.environmentIntensity = 1.0;
/**
* Specifies that the specular weight is stored in the alpha channel of the specular weight texture.
*/
this.useSpecularWeightFromTextureAlpha = false;
/**
* Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
*/
this.forceAlphaTest = false;
/**
* Defines the alpha limits in alpha test mode.
*/
this.alphaCutOff = 0.4;
/**
* Specifies if the metallic texture contains the ambient occlusion information in its red channel.
*/
this.useAmbientOcclusionFromMetallicTextureRed = false;
/**
* Specifies if the ambient texture contains the ambient occlusion information in its red channel only.
*/
this.useAmbientInGrayScale = false;
/**
* Allows using an object space normal map (instead of tangent space).
*/
this.useObjectSpaceNormalMap = false;
/**
* Allows using the normal map in parallax mode.
*/
this.useParallax = false;
/**
* Allows using the normal map in parallax occlusion mode.
*/
this.useParallaxOcclusion = false;
/**
* Controls the scale bias of the parallax mode.
*/
this.parallaxScaleBias = 0.05;
/**
* If sets to true, disables all the lights affecting the material.
*/
this.disableLighting = false;
/**
* Force the shader to compute irradiance in the fragment shader in order to take normal mapping into account.
*/
this.forceIrradianceInFragment = false;
/**
* Number of Simultaneous lights allowed on the material.
*/
this.maxSimultaneousLights = 4;
/**
* If sets to true, x component of normal map value will invert (x = 1.0 - x).
*/
this.invertNormalMapX = false;
/**
* If sets to true, y component of normal map value will invert (y = 1.0 - y).
*/
this.invertNormalMapY = false;
/**
* If sets to true and backfaceCulling is false, normals will be flipped on the backside.
*/
this.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)
*/
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)
*/
this.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
*/
this.environmentBRDFTexture = null;
/**
* Force normal to face away from face.
*/
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 normalmap values.
*/
this.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).
*/
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.
*/
this.useRadianceOcclusion = true;
/**
* 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 stores the direct, emissive, environment, and specular light intensities into a Vector4.
*/
this._lightingInfos = new Vector4(this.directIntensity, 1.0, this.environmentIntensity, 1.0);
/**
* Stores the radiance (and, possibly, irradiance) values in a texture.
* @internal
*/
this._radianceTexture = null;
/**
* Specifies that the specular weight will be read from the alpha channel.
* This is for compatibility with glTF's KHR_materials_specular extension.
* @internal
*/
this._useSpecularWeightFromAlpha = false;
/**
* Specifies that the specular weight will be read from the alpha channel of the specular color texture.
* This is for compatibility with glTF's KHR_materials_specular extension.
* @internal
*/
this._useSpecularWeightFromSpecularColorTexture = false;
/**
* Specifies if the material uses anisotropy weight read from the geometry tangent texture's blue channel.
* This is for compatibility with glTF's anisotropy extension.
* @internal
*/
this._useSpecularRoughnessAnisotropyFromTangentTexture = false;
/**
* Specifies if the material uses coat anisotropy weight read from the coat's geometry tangent texture's blue channel.
* This is for compatibility with glTF's clearcoat_anisotropy extension.
* @internal
*/
this._useCoatRoughnessAnisotropyFromTangentTexture = false;
/**
* Specifies whether the coat roughness is taken from the green channel of the coat texture.
* This is for compatibility with glTF's KHR_materials_clearcoat and KHR_materials_coat extensions.
* @internal
*/
this._useCoatRoughnessFromGreenChannel = false;
/**
* Assume the anisotropy data is stored in the format specified by
* KHR_materials_anisotropy.
* @internal
*/
this._useGltfStyleAnisotropy = false;
/**
* Specifies that the fuzz roughness is stored in the alpha channel of the texture.
* This is for compatibility with glTF where the fuzz roughness is often stored in
* the alpha channel of the fuzz color texture.
*/
this._useFuzzRoughnessFromTextureAlpha = 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 from the base color texture's alpha channel.
* This is for compatibility with glTF.
* @internal
*/
this._useAlphaFromBaseColorTexture = false;
/**
* Specifies if the metallic texture contains the ambient occlusion information in its red channel.
* This is for compatibility with glTF.
* @internal
*/
this._useAmbientOcclusionFromMetallicTextureRed = false;
/**
* Specifies if the metallic texture contains the roughness information in its green channel.
* This is for compatibility with glTF.
* @internal
*/
this._useRoughnessFromMetallicTextureGreen = false;
/**
* Specifies if the metallic texture contains the metallic information in its blue channel.
* This is for compatibility with glTF.
* @internal
*/
this._useMetallicFromMetallicTextureBlue = false;
/**
* Specifies if the thin film thickness is stored in the green channel of the thin film thickness texture.
* This is for compatibility with glTF.
* @internal
*/
this._useThinFilmThicknessFromTextureGreen = false;
/**
* Specifies if the geometry thickness is stored in the green channel of the geometry thickness texture.
* This is for compatibility with glTF.
* @internal
*/
this._useGeometryThicknessFromGreenChannel = false;
/**
* Defines the falloff type used in this material.
* It by default is Physical.
* @internal
*/
this._lightFalloff = Material.LIGHTFALLOFF_PHYSICAL;
/**
* Allows using an object space normal map (instead of tangent space).
* @internal
*/
this._useObjectSpaceNormalMap = false;
/**
* Allows using the normal map in parallax mode.
* @internal
*/
this._useParallax = false;
/**
* Allows using the normal 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;
/**
* Specifies the environment BRDF texture used to compute the scale and offset roughness values
* from cos theta and roughness for the fuzz layer:
* https://github.com/tizian/ltc-sheen?tab=readme-ov-file
* @internal
*/
this._environmentFuzzBRDFTexture = null;
this._backgroundRefractionTexture = null;
/**
* Force the shader to compute irradiance in the fragment shader in order to take normal mapping into account.
* @internal
*/
this._forceIrradianceInFragment = false;
this._realTimeFiltering = false;
this._realTimeFilteringQuality = 8;
this._fuzzSampleNumber = 4;
/**
* 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 normalmap values.
* @internal
*/
this._enableSpecularAntiAliasing = false;
/**
* Stores the available render targets.
*/
this._renderTargets = new SmartArray(16);
/**
* 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;
this._vertexPullingMetadata = null;
/**
* @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._transparencyMode = Material.MATERIAL_OPAQUE;
// TODO: Check if we're running WebGL 2.0 or above
if (this.getScene() && !this.getScene()?.getEngine().isWebGPU && this.getScene().getEngine().webGLVersion < 2) {
Logger.Error("OpenPBRMaterial: WebGL 2.0 or above is required for this material.");
}
if (!OpenPBRMaterial._noiseTextures[this.getScene().uniqueId]) {
OpenPBRMaterial._noiseTextures[this.getScene().uniqueId] = new Texture(Tools.GetAssetUrl("https://assets.babylonjs.com/core/blue_noise/blue_noise_rgb.png"), this.getScene(), false, true, 1);
this.getScene().onDisposeObservable.addOnce(() => {
OpenPBRMaterial._noiseTextures[this.getScene().uniqueId]?.dispose();
delete OpenPBRMaterial._noiseTextures[this.getScene().uniqueId];
});
}
// Setup the default processing configuration to the scene.
this._attachImageProcessingConfiguration(null);
this.getRenderTargetTextures = () => {
this._renderTargets.reset();
if (MaterialFlags.ReflectionTextureEnabled && this._radianceTexture && this._radianceTexture.isRenderTarget) {
this._renderTargets.push(this._radianceTexture);
}
if (MaterialFlags.RefractionTextureEnabled && this._backgroundRefractionTexture && this._backgroundRefractionTexture.isRenderTarget) {
this._renderTargets.push(this._backgroundRefractionTexture);
}
this._eventInfo.renderTargets = this._renderTargets;
this._callbackPluginEventFillRenderTargetTextures(this._eventInfo);
return this._renderTargets;
};
this._environmentBRDFTexture = GetEnvironmentBRDFTexture(this.getScene());
this._environmentFuzzBRDFTexture = GetEnvironmentFuzzBRDFTexture(this.getScene());
this.prePassConfiguration = new PrePassConfiguration();
// 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[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[key];
if (value instanceof Sampler) {
this._samplersList[key] = value;
}
}
// For each sampler in _samplersList, add defines to be added to OpenPBRMaterialDefines
for (const samplerKey in this._samplersList) {
const sampler = this._samplersList[samplerKey];
const defineName = sampler.textureDefine;
this._samplerDefines[defineName] = { type: "boolean", default: false };
this._samplerDefines[defineName + "DIRECTUV"] = { type: "number", default: 0 };
this._samplerDefines[defineName + "_GAMMA"] = { type: "boolean", default: false };
}
// Arg. Why do I have to add these references to get rid of the linting errors?
this._baseWeight;
this._baseWeightTexture;
this._baseColor;
this._baseColorTexture;
this._baseDiffuseRoughness;
this._baseDiffuseRoughnessTexture;
this._baseMetalness;
this._baseMetalnessTexture;
this._specularWeight;
this._specularWeightTexture;
this._specularColor;
this._specularColorTexture;
this._specularRoughness;
this._specularIor;
this._specularRoughnessTexture;
this._specularRoughnessAnisotropy;
this._specularRoughnessAnisotropyTexture;
this._transmissionWeight;
this._transmissionWeightTexture;
this._transmissionColor;
this._transmissionColorTexture;
this._transmissionDepth;
this._transmissionDepthTexture;
this._transmissionScatter;
this._transmissionScatterTexture;
this._transmissionScatterAnisotropy;
this._transmissionDispersionScale;
this._transmissionDispersionScaleTexture;
this._transmissionDispersionAbbeNumber;
this._coatWeight;
this._coatWeightTexture;
this._coatColor;
this._coatColorTexture;
this._coatRoughness;
this._coatRoughnessTexture;
this._coatRoughnessAnisotropy;
this._coatRoughnessAnisotropyTexture;
this._coatIor;
this._coatDarkening;
this._coatDarkeningTexture;
this._fuzzWeight;
this._fuzzWeightTexture;
this._fuzzColor;
this._fuzzColorTexture;
this._fuzzRoughness;
this._fuzzRoughnessTexture;
this._geometryNormalTexture;
this._geometryTangent;
this._geometryTangentTexture;
this._geometryCoatNormalTexture;
this._geometryCoatTangent;
this._geometryCoatTangentTexture;
this._geometryOpacity;
this._geometryOpacityTexture;
this._geometryThickness;
this._geometryThicknessTexture;
this._thinFilmWeight;
this._thinFilmWeightTexture;
this._thinFilmThickness;
this._thinFilmThicknessMin;
this._thinFilmThicknessTexture;
this._thinFilmIor;
this._emissionLuminance;
this._emissionColor;
this._emissionColorTexture;
this._ambientOcclusionTexture;
}
/**
* Gets a boolean indicating that current material needs to register RTT