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,081 lines (1,079 loc) 117 kB
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