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,042 lines (1,040 loc) 75.7 kB
import { __decorate } from "../tslib.es6.js"; /* eslint-disable @typescript-eslint/naming-convention */ import { serialize, serializeAsColor3, expandToProperty, serializeAsFresnelParameters, serializeAsTexture } from "../Misc/decorators.js"; import { SmartArray } from "../Misc/smartArray.js"; import { Scene } from "../scene.js"; import { Color3 } from "../Maths/math.color.js"; import { VertexBuffer } from "../Buffers/buffer.js"; import { PrePassConfiguration } from "./prePassConfiguration.js"; import { ImageProcessingDefinesMixin } from "./imageProcessingConfiguration.defines.js"; import { ImageProcessingConfiguration } from "./imageProcessingConfiguration.js"; import { Material } from "../Materials/material.js"; import { MaterialDefines } from "../Materials/materialDefines.js"; import { PushMaterial } from "./pushMaterial.js"; import { RegisterClass } from "../Misc/typeStore.js"; import { MaterialFlags } from "./materialFlags.js"; import { EffectFallbacks } from "./effectFallbacks.js"; import { DetailMapConfiguration } from "./material.detailMapConfiguration.js"; import { AddClipPlaneUniforms, BindClipPlane } from "./clipPlaneMaterialHelper.js"; import { PrepareVertexPullingUniforms, BindVertexPullingUniforms } from "./vertexPullingHelper.functions.js"; import { BindBonesParameters, BindFogParameters, BindLights, BindLogDepth, BindMorphTargetParameters, BindTextureMatrix, BindIBLParameters, HandleFallbacksForShadows, PrepareAttributesForBakedVertexAnimation, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareAttributesForMorphTargets, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareDefinesForOIT, PrepareDefinesForPrePass, PrepareUniformsAndSamplersForIBL, PrepareUniformsAndSamplersList, PrepareUniformLayoutForIBL, } from "./materialHelper.functions.js"; import { SerializationHelper } from "../Misc/decorators.serialization.js"; import { MaterialHelperGeometryRendering } from "./materialHelper.geometryrendering.js"; import { UVDefinesMixin } from "./uv.defines.js"; import { ImageProcessingMixin } from "./imageProcessing.js"; const onCreatedEffectParameters = { effect: null, subMesh: null }; class StandardMaterialDefinesBase extends UVDefinesMixin(MaterialDefines) { } /** @internal */ export class StandardMaterialDefines extends ImageProcessingDefinesMixin(StandardMaterialDefinesBase) { /** * Initializes the Standard Material defines. * @param externalProperties The external properties */ constructor(externalProperties) { super(externalProperties); this.DIFFUSE = false; this.DIFFUSEDIRECTUV = 0; this.BAKED_VERTEX_ANIMATION_TEXTURE = false; this.AMBIENT = false; this.AMBIENTDIRECTUV = 0; this.OPACITY = false; this.OPACITYDIRECTUV = 0; this.OPACITYRGB = false; this.REFLECTION = false; this.EMISSIVE = false; this.EMISSIVEDIRECTUV = 0; this.SPECULAR = false; this.SPECULARDIRECTUV = 0; this.BUMP = false; this.BUMPDIRECTUV = 0; this.PARALLAX = false; this.PARALLAX_RHS = false; this.PARALLAXOCCLUSION = false; this.SPECULAROVERALPHA = false; this.CLIPPLANE = false; this.CLIPPLANE2 = false; this.CLIPPLANE3 = false; this.CLIPPLANE4 = false; this.CLIPPLANE5 = false; this.CLIPPLANE6 = false; this.ALPHATEST = false; this.DEPTHPREPASS = false; this.ALPHAFROMDIFFUSE = false; this.POINTSIZE = false; this.FOG = false; this.SPECULARTERM = false; this.DIFFUSEFRESNEL = false; this.OPACITYFRESNEL = false; this.REFLECTIONFRESNEL = false; this.REFRACTIONFRESNEL = false; this.EMISSIVEFRESNEL = false; this.FRESNEL = false; this.NORMAL = false; this.TANGENT = false; this.VERTEXCOLOR = false; this.VERTEXALPHA = false; this.NUM_BONE_INFLUENCERS = 0; this.BonesPerMesh = 0; this.BONETEXTURE = false; this.BONES_VELOCITY_ENABLED = false; this.INSTANCES = false; this.THIN_INSTANCES = false; this.INSTANCESCOLOR = false; this.GLOSSINESS = false; this.ROUGHNESS = false; this.EMISSIVEASILLUMINATION = false; this.LINKEMISSIVEWITHDIFFUSE = false; this.REFLECTIONFRESNELFROMSPECULAR = false; this.LIGHTMAP = false; this.LIGHTMAPDIRECTUV = 0; this.OBJECTSPACE_NORMALMAP = false; this.USELIGHTMAPASSHADOWMAP = false; this.REFLECTIONMAP_3D = false; this.REFLECTIONMAP_SPHERICAL = false; this.REFLECTIONMAP_PLANAR = false; this.REFLECTIONMAP_CUBIC = false; this.USE_LOCAL_REFLECTIONMAP_CUBIC = false; this.USE_LOCAL_REFRACTIONMAP_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.REFLECTIONMAP_OPPOSITEZ = false; this.INVERTCUBICMAP = false; this.LOGARITHMICDEPTH = false; this.REFRACTION = false; this.REFRACTIONMAP_3D = false; this.REFLECTIONOVERALPHA = false; this.TWOSIDEDLIGHTING = false; this.SHADOWFLOAT = 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.NONUNIFORMSCALING = false; // https://playground.babylonjs.com#V6DWIH this.PREMULTIPLYALPHA = false; // https://playground.babylonjs.com#LNVJJ7 this.ALPHATEST_AFTERALLALPHACOMPUTATIONS = false; this.ALPHABLEND = true; 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.RGBDLIGHTMAP = false; this.RGBDREFLECTION = false; this.RGBDREFRACTION = false; this.MULTIVIEW = false; this.ORDER_INDEPENDENT_TRANSPARENCY = false; this.ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false; this.CAMERA_ORTHOGRAPHIC = false; this.CAMERA_PERSPECTIVE = false; this.AREALIGHTSUPPORTED = true; 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; /** * If the reflection texture on this material is in linear color space * @internal */ this.IS_REFLECTION_LINEAR = false; /** * If the refraction texture on this material is in linear color space * @internal */ this.IS_REFRACTION_LINEAR = false; this.DECAL_AFTER_DETAIL = false; this.rebuild(); } } class StandardMaterialBase extends ImageProcessingMixin(PushMaterial) { } /** * This is the default material used in Babylon. It is the best trade off between quality * and performances. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/materials_introduction */ export class StandardMaterial extends StandardMaterialBase { /** * Can this material render to prepass */ get isPrePassCapable() { return !this.disableDepthWrite; } /** * Can this material render to several textures at once */ get canRenderToMRT() { return true; } /** * Instantiates a new standard material. * This is the default material used in Babylon. It is the best trade off between quality * and performances. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/materials_introduction * @param name Define the name of the material in the scene * @param scene Define the scene the material belong to * @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 || StandardMaterial.ForceGLSL); this._diffuseTexture = null; this._ambientTexture = null; this._opacityTexture = null; this._reflectionTexture = null; this._emissiveTexture = null; this._specularTexture = null; this._bumpTexture = null; this._lightmapTexture = null; this._refractionTexture = null; /** * The color of the material lit by the environmental background lighting. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/materials_introduction#ambient-color-example */ this.ambientColor = new Color3(0, 0, 0); /** * The basic color of the material as viewed under a light. */ this.diffuseColor = new Color3(1, 1, 1); /** * Define how the color and intensity of the highlight given by the light in the material. */ this.specularColor = new Color3(1, 1, 1); /** * Define the color of the material as if self lit. * This will be mixed in the final result even in the absence of light. */ this.emissiveColor = new Color3(0, 0, 0); /** * Defines how sharp are the highlights in the material. * The bigger the value the sharper giving a more glossy feeling to the result. * Reversely, the smaller the value the blurrier giving a more rough feeling to the result. */ this.specularPower = 64; this._useAlphaFromDiffuseTexture = false; this._useEmissiveAsIllumination = false; this._linkEmissiveWithDiffuse = false; this._useSpecularOverAlpha = false; this._useReflectionOverAlpha = false; this._disableLighting = false; this._useObjectSpaceNormalMap = false; this._useParallax = false; this._useParallaxOcclusion = false; /** * Apply a scaling factor that determine which "depth" the height map should reprensent. A value between 0.05 and 0.1 is reasonnable in Parallax, you can reach 0.2 using Parallax Occlusion. */ this.parallaxScaleBias = 0.05; this._roughness = 0; /** * In case of refraction, define the value of the index of refraction. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/reflectionTexture#how-to-obtain-reflections-and-refractions */ this.indexOfRefraction = 0.98; /** * Invert the refraction texture alongside the y axis. * It can be useful with procedural textures or probe for instance. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/reflectionTexture#how-to-obtain-reflections-and-refractions */ this.invertRefractionY = true; /** * Defines the alpha limits in alpha test mode. */ this.alphaCutOff = 0.4; this._useLightmapAsShadowmap = false; this._useReflectionFresnelFromSpecular = false; this._useGlossinessFromSpecularMapAlpha = false; this._maxSimultaneousLights = 4; this._invertNormalMapX = false; this._invertNormalMapY = false; this._twoSidedLighting = false; this._applyDecalMapAfterDetailMap = false; this._shadersLoaded = false; this._vertexPullingMetadata = null; this._renderTargets = new SmartArray(16); this._globalAmbientColor = new Color3(0, 0, 0); this._cacheHasRenderTargetTextures = false; this.detailMap = new DetailMapConfiguration(this); // Setup the default processing configuration to the scene. this._attachImageProcessingConfiguration(null); this.prePassConfiguration = new PrePassConfiguration(); this.getRenderTargetTextures = () => { this._renderTargets.reset(); if (StandardMaterial.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { this._renderTargets.push(this._reflectionTexture); } if (StandardMaterial.RefractionTextureEnabled && this._refractionTexture && this._refractionTexture.isRenderTarget) { this._renderTargets.push(this._refractionTexture); } this._eventInfo.renderTargets = this._renderTargets; this._callbackPluginEventFillRenderTargetTextures(this._eventInfo); return this._renderTargets; }; } /** * Gets a boolean indicating that current material needs to register RTT */ get hasRenderTargetTextures() { if (StandardMaterial.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) { return true; } if (StandardMaterial.RefractionTextureEnabled && this._refractionTexture && this._refractionTexture.isRenderTarget) { return true; } return this._cacheHasRenderTargetTextures; } /** * Gets the current class name of the material e.g. "StandardMaterial" * Mainly use in serialization. * @returns the class name */ getClassName() { return "StandardMaterial"; } /** * Specifies if the material will require alpha blending * @returns a boolean specifying if alpha blending is needed */ needAlphaBlending() { if (this._hasTransparencyMode) { return this._transparencyModeIsBlend; } if (this._disableAlphaBlending) { return false; } return (this.alpha < 1.0 || this._opacityTexture != null || this._shouldUseAlphaFromDiffuseTexture() || (this._opacityFresnelParameters && this._opacityFresnelParameters.isEnabled)); } /** * Specifies if this material should be rendered in alpha test mode * @returns a boolean specifying if an alpha test is needed. */ needAlphaTesting() { if (this._hasTransparencyMode) { return this._transparencyModeIsTest; } return this._hasAlphaChannel() && (this._transparencyMode == null || this._transparencyMode === Material.MATERIAL_ALPHATEST); } /** * @returns whether or not the alpha value of the diffuse texture should be used for alpha blending. */ _shouldUseAlphaFromDiffuseTexture() { return this._diffuseTexture != null && this._diffuseTexture.hasAlpha && this._useAlphaFromDiffuseTexture && this._transparencyMode !== Material.MATERIAL_OPAQUE; } /** * @returns whether or not there is a usable alpha channel for transparency. */ _hasAlphaChannel() { return (this._diffuseTexture != null && this._diffuseTexture.hasAlpha) || this._opacityTexture != null; } /** * Get the texture used for alpha test purpose. * @returns the diffuse texture in case of the standard material. */ getAlphaTestTexture() { return this._diffuseTexture; } /** * Get if the submesh is ready to be used and all its information available. * Child classes can use it to update shaders * @param mesh defines the mesh to check * @param subMesh defines which submesh to check * @param useInstances specifies that instances should be used * @returns a boolean indicating that the submesh is ready or not */ isReadyForSubMesh(mesh, subMesh, useInstances = false) { 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 StandardMaterialDefines(this._eventInfo.defineNames); } const scene = this.getScene(); const defines = subMesh.materialDefines; if (this._isReadyForSubMesh(subMesh)) { return true; } const engine = scene.getEngine(); // Lights defines._needNormals = PrepareDefinesForLights(scene, mesh, defines, true, this._maxSimultaneousLights, this._disableLighting); // Multiview PrepareDefinesForMultiview(scene, defines); // PrePass const oit = this.needAlphaBlendingForMesh(mesh) && this.getScene().useOrderIndependentTransparency; PrepareDefinesForPrePass(scene, defines, this.canRenderToMRT && !oit); // Order independant transparency PrepareDefinesForOIT(scene, defines, oit); MaterialHelperGeometryRendering.PrepareDefines(engine.currentRenderPassId, mesh, defines); // Textures if (defines._areTexturesDirty) { this._eventInfo.hasRenderTargetTextures = false; this._callbackPluginEventHasRenderTargetTextures(this._eventInfo); this._cacheHasRenderTargetTextures = this._eventInfo.hasRenderTargetTextures; defines._needUVs = false; for (let i = 1; i <= 6; ++i) { defines["MAINUV" + i] = false; } if (scene.texturesEnabled) { defines.DIFFUSEDIRECTUV = 0; defines.BUMPDIRECTUV = 0; defines.AMBIENTDIRECTUV = 0; defines.OPACITYDIRECTUV = 0; defines.EMISSIVEDIRECTUV = 0; defines.SPECULARDIRECTUV = 0; defines.LIGHTMAPDIRECTUV = 0; if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) { if (!this._diffuseTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._diffuseTexture, defines, "DIFFUSE"); } } else { defines.DIFFUSE = false; } if (this._ambientTexture && StandardMaterial.AmbientTextureEnabled) { if (!this._ambientTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._ambientTexture, defines, "AMBIENT"); } } else { defines.AMBIENT = false; } if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) { if (!this._opacityTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._opacityTexture, defines, "OPACITY"); defines.OPACITYRGB = this._opacityTexture.getAlphaFromRGB; } } else { defines.OPACITY = false; } if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) { defines.ROUGHNESS = this._roughness > 0; defines.REFLECTIONOVERALPHA = this._useReflectionOverAlpha; } else { defines.ROUGHNESS = false; defines.REFLECTIONOVERALPHA = false; } if (!PrepareDefinesForIBL(scene, this._reflectionTexture, defines)) { return false; } if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { if (!this._emissiveTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._emissiveTexture, defines, "EMISSIVE"); } } else { defines.EMISSIVE = false; } if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) { if (!this._lightmapTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._lightmapTexture, defines, "LIGHTMAP"); defines.USELIGHTMAPASSHADOWMAP = this._useLightmapAsShadowmap; defines.RGBDLIGHTMAP = this._lightmapTexture.isRGBD; } } else { defines.LIGHTMAP = false; } if (this._specularTexture && StandardMaterial.SpecularTextureEnabled) { if (!this._specularTexture.isReadyOrNotBlocking()) { return false; } else { PrepareDefinesForMergedUV(this._specularTexture, defines, "SPECULAR"); defines.GLOSSINESS = this._useGlossinessFromSpecularMapAlpha; } } else { defines.SPECULAR = false; } if (scene.getEngine().getCaps().standardDerivatives && this._bumpTexture && StandardMaterial.BumpTextureEnabled) { // Bump texture can not be not blocking. if (!this._bumpTexture.isReady()) { return false; } else { PrepareDefinesForMergedUV(this._bumpTexture, defines, "BUMP"); defines.PARALLAX = this._useParallax; defines.PARALLAX_RHS = scene.useRightHandedSystem; defines.PARALLAXOCCLUSION = this._useParallaxOcclusion; } defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap; } else { defines.BUMP = false; defines.PARALLAX = false; defines.PARALLAX_RHS = false; defines.PARALLAXOCCLUSION = false; } if (this._refractionTexture && StandardMaterial.RefractionTextureEnabled) { if (!this._refractionTexture.isReadyOrNotBlocking()) { return false; } else { defines._needUVs = true; defines.REFRACTION = true; defines.REFRACTIONMAP_3D = this._refractionTexture.isCube; defines.RGBDREFRACTION = this._refractionTexture.isRGBD; defines.USE_LOCAL_REFRACTIONMAP_CUBIC = this._refractionTexture.boundingBoxSize ? true : false; } } else { defines.REFRACTION = false; } defines.TWOSIDEDLIGHTING = !this._backFaceCulling && this._twoSidedLighting; } else { defines.DIFFUSE = false; defines.AMBIENT = false; defines.OPACITY = false; defines.REFLECTION = false; defines.EMISSIVE = false; defines.LIGHTMAP = false; defines.BUMP = false; defines.REFRACTION = false; } defines.ALPHAFROMDIFFUSE = this._shouldUseAlphaFromDiffuseTexture(); defines.EMISSIVEASILLUMINATION = this._useEmissiveAsIllumination; defines.LINKEMISSIVEWITHDIFFUSE = this._linkEmissiveWithDiffuse; defines.SPECULAROVERALPHA = this._useSpecularOverAlpha; defines.PREMULTIPLYALPHA = this.alphaMode === 7 || this.alphaMode === 8; defines.ALPHATEST_AFTERALLALPHACOMPUTATIONS = this.transparencyMode !== null; defines.ALPHABLEND = this.transparencyMode === null || this.needAlphaBlendingForMesh(mesh); // check on null for backward compatibility } 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; } this._imageProcessingConfiguration.prepareDefines(defines); defines.IS_REFLECTION_LINEAR = this.reflectionTexture != null && !this.reflectionTexture.gammaSpace; defines.IS_REFRACTION_LINEAR = this.refractionTexture != null && !this.refractionTexture.gammaSpace; } if (defines._areFresnelDirty) { if (StandardMaterial.FresnelEnabled) { // Fresnel if (this._diffuseFresnelParameters || this._opacityFresnelParameters || this._emissiveFresnelParameters || this._refractionFresnelParameters || this._reflectionFresnelParameters) { defines.DIFFUSEFRESNEL = this._diffuseFresnelParameters && this._diffuseFresnelParameters.isEnabled; defines.OPACITYFRESNEL = this._opacityFresnelParameters && this._opacityFresnelParameters.isEnabled; defines.REFLECTIONFRESNEL = this._reflectionFresnelParameters && this._reflectionFresnelParameters.isEnabled; defines.REFLECTIONFRESNELFROMSPECULAR = this._useReflectionFresnelFromSpecular; defines.REFRACTIONFRESNEL = this._refractionFresnelParameters && this._refractionFresnelParameters.isEnabled; defines.EMISSIVEFRESNEL = this._emissiveFresnelParameters && this._emissiveFresnelParameters.isEnabled; defines._needNormals = true; defines.FRESNEL = true; } } else { defines.FRESNEL = false; } } // Check if lights are ready if (defines["AREALIGHTUSED"] || defines["CLUSTLIGHT_BATCH"]) { for (let index = 0; index < mesh.lightSources.length; index++) { if (!mesh.lightSources[index]._isReady()) { return false; } } } // Misc. PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines, this._applyDecalMapAfterDetailMap, this._useVertexPulling, subMesh.getRenderingMesh(), this._isVertexOutputInvariant); // Values that need to be evaluated on every frame PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances, null, subMesh.getRenderingMesh().hasThinInstances); // External config this._eventInfo.defines = defines; this._eventInfo.mesh = mesh; this._callbackPluginEventPrepareDefinesBeforeAttributes(this._eventInfo); // Attribs PrepareDefinesForAttributes(mesh, defines, true, true, true); // External config this._callbackPluginEventPrepareDefines(this._eventInfo); // Get correct effect let forceWasNotReadyPreviously = false; if (defines.isDirty) { const lightDisposed = defines._areLightsDisposed; defines.markAsProcessed(); // Fallbacks const fallbacks = new EffectFallbacks(); if (defines.REFLECTION) { fallbacks.addFallback(0, "REFLECTION"); } if (defines.SPECULAR) { fallbacks.addFallback(0, "SPECULAR"); } if (defines.BUMP) { fallbacks.addFallback(0, "BUMP"); } if (defines.PARALLAX) { fallbacks.addFallback(1, "PARALLAX"); } if (defines.PARALLAX_RHS) { fallbacks.addFallback(1, "PARALLAX_RHS"); } if (defines.PARALLAXOCCLUSION) { fallbacks.addFallback(0, "PARALLAXOCCLUSION"); } if (defines.SPECULAROVERALPHA) { fallbacks.addFallback(0, "SPECULAROVERALPHA"); } if (defines.FOG) { fallbacks.addFallback(1, "FOG"); } if (defines.POINTSIZE) { fallbacks.addFallback(0, "POINTSIZE"); } if (defines.LOGARITHMICDEPTH) { fallbacks.addFallback(0, "LOGARITHMICDEPTH"); } HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights); if (defines.SPECULARTERM) { fallbacks.addFallback(0, "SPECULARTERM"); } if (defines.DIFFUSEFRESNEL) { fallbacks.addFallback(1, "DIFFUSEFRESNEL"); } if (defines.OPACITYFRESNEL) { fallbacks.addFallback(2, "OPACITYFRESNEL"); } if (defines.REFLECTIONFRESNEL) { fallbacks.addFallback(3, "REFLECTIONFRESNEL"); } if (defines.EMISSIVEFRESNEL) { fallbacks.addFallback(4, "EMISSIVEFRESNEL"); } if (defines.FRESNEL) { fallbacks.addFallback(4, "FRESNEL"); } 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 = "default"; const uniforms = [ "world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor", "visibility", "vFogInfos", "vFogColor", "pointSize", "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos", "mBones", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "normalMatrix", "lightmapMatrix", "refractionMatrix", "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor", "vRefractionPosition", "vRefractionSize", "logarithmicDepthConstant", "vTangentSpaceParams", "alphaCutOff", "boneTextureInfo", "morphTargetTextureInfo", "morphTargetTextureIndices", "cameraInfo", ]; const samplers = [ "diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler", "boneSampler", "morphTargets", "oitDepthSampler", "oitFrontColorSampler", "areaLightsLTC1Sampler", "areaLightsLTC2Sampler", ]; PrepareUniformsAndSamplersForIBL(uniforms, samplers, false); const uniformBuffers = ["Material", "Scene", "Mesh"]; const indexParameters = { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }; this._eventInfo.fallbacks = fallbacks; this._eventInfo.fallbackRank = 0; 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); if (ImageProcessingConfiguration) { ImageProcessingConfiguration.PrepareUniforms(uniforms, defines); ImageProcessingConfiguration.PrepareSamplers(samplers, defines); } PrepareUniformsAndSamplersList({ uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: defines, maxSimultaneousLights: this._maxSimultaneousLights, }); AddClipPlaneUniforms(uniforms); // Vertex pulling metadata uniforms if (this._useVertexPulling) { const renderingMesh = subMesh.getRenderingMesh(); const geometry = renderingMesh?.geometry; if (geometry) { this._vertexPullingMetadata = PrepareVertexPullingUniforms(geometry); if (this._vertexPullingMetadata) { this._vertexPullingMetadata.forEach((_, attribute) => { uniforms.push(`vp_${attribute}_info`); }); } } } else { this._vertexPullingMetadata = null; } const csnrOptions = {}; if (this.customShaderNameResolve) { shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs, csnrOptions); } const join = defines.toString(); const previousEffect = subMesh.effect; const effect = scene.getEngine().createEffect(shaderName, { attributes: attribs, uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: join, fallbacks: fallbacks, onCompiled: this.onCompiled, onError: this.onError, indexParameters, processFinalCode: csnrOptions.processFinalCode, processCodeAfterIncludes: this._eventInfo.customCode, multiTarget: defines.PREPASS, shaderLanguage: this._shaderLanguage, extraInitializationsAsync: this._shadersLoaded ? undefined : async () => { if (this._shaderLanguage === 1 /* ShaderLanguage.WGSL */) { await Promise.all([import("../ShadersWGSL/default.vertex.js"), import("../ShadersWGSL/default.fragment.js")]); } else { await Promise.all([import("../Shaders/default.vertex.js"), import("../Shaders/default.fragment.js")]); } this._shadersLoaded = true; }, }, engine); this._eventInfo.customCode = undefined; 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()) { 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; } /** * Builds the material UBO layouts. * Used internally during the effect preparation. */ buildUniformLayout() { // Order is important ! const ubo = this._uniformBuffer; ubo.addUniform("diffuseLeftColor", 4); ubo.addUniform("diffuseRightColor", 4); ubo.addUniform("opacityParts", 4); ubo.addUniform("reflectionLeftColor", 4); ubo.addUniform("reflectionRightColor", 4); ubo.addUniform("refractionLeftColor", 4); ubo.addUniform("refractionRightColor", 4); ubo.addUniform("emissiveLeftColor", 4); ubo.addUniform("emissiveRightColor", 4); ubo.addUniform("vDiffuseInfos", 2); ubo.addUniform("vAmbientInfos", 2); ubo.addUniform("vOpacityInfos", 2); ubo.addUniform("vEmissiveInfos", 2); ubo.addUniform("vLightmapInfos", 2); ubo.addUniform("vSpecularInfos", 2); ubo.addUniform("vBumpInfos", 3); ubo.addUniform("diffuseMatrix", 16); ubo.addUniform("ambientMatrix", 16); ubo.addUniform("opacityMatrix", 16); ubo.addUniform("emissiveMatrix", 16); ubo.addUniform("lightmapMatrix", 16); ubo.addUniform("specularMatrix", 16); ubo.addUniform("bumpMatrix", 16); ubo.addUniform("vTangentSpaceParams", 2); ubo.addUniform("pointSize", 1); ubo.addUniform("alphaCutOff", 1); ubo.addUniform("refractionMatrix", 16); ubo.addUniform("vRefractionInfos", 4); ubo.addUniform("vRefractionPosition", 3); ubo.addUniform("vRefractionSize", 3); ubo.addUniform("vSpecularColor", 4); ubo.addUniform("vEmissiveColor", 3); ubo.addUniform("vDiffuseColor", 4); ubo.addUniform("vAmbientColor", 3); ubo.addUniform("cameraInfo", 4); PrepareUniformLayoutForIBL(ubo, false, true); super.buildUniformLayout(); } /** * Binds the submesh to this material by preparing the effect and shader to draw * @param world defines the world transformation matrix * @param mesh defines the mesh containing the submesh * @param subMesh defines the submesh to bind the material to */ bindForSubMesh(world, mesh, subMesh) { const scene = this.getScene(); const defines = subMesh.materialDefines; if (!defines) { return; } const effect = subMesh.effect; if (!effect) { return; } this._activeEffect = effect; // Matrices Mesh. mesh.getMeshUniformBuffer().bindToEffect(effect, "Mesh"); mesh.transferToEffect(world); // Binding unconditionally this._uniformBuffer.bindToEffect(effect, "Material"); this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen); MaterialHelperGeometryRendering.Bind(scene.getEngine().currentRenderPassId, this._activeEffect, mesh, world, this); const camera = scene.activeCamera; if (camera) { this._uniformBuffer.updateFloat4("cameraInfo", camera.minZ, camera.maxZ, 0, 0); } else { this._uniformBuffer.updateFloat4("cameraInfo", 0, 0, 0, 0); } this._eventInfo.subMesh = subMesh; this._callbackPluginEventHardBindForSubMesh(this._eventInfo); // Normal Matrix if (defines.OBJECTSPACE_NORMALMAP) { world.toNormalMatrix(this._normalMatrix); this.bindOnlyNormalMatrix(this._normalMatrix); } const mustRebind = this._mustRebind(scene, effect, subMesh, mesh.visibility); // Bones BindBonesParameters(mesh, effect); // Vertex pulling if (this._vertexPullingMetadata) { BindVertexPullingUniforms(effect, this._vertexPullingMetadata); } const ubo = this._uniformBuffer; if (mustRebind) { this.bindViewProjection(effect); if (!ubo.useUbo || !this.isFrozen || !ubo.isSync || subMesh._drawWrapper._forceRebindOnNextCall) { if (StandardMaterial.FresnelEnabled && defines.FRESNEL) { // Fresnel if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) { ubo.updateColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power); ubo.updateColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias); } if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) { ubo.updateColor4("opacityParts", new Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power); } if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) { ubo.updateColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power); ubo.updateColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias); } if (this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled) { ubo.updateColor4("refractionLeftColor", this.refractionFresnelParameters.leftColor, this.refractionFresnelParameters.power); ubo.updateColor4("refractionRightColor", this.refractionFresnelParameters.rightColor, this.refractionFresnelParameters.bias); } if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) { ubo.updateColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power); ubo.updateColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias); } } // Textures if (scene.texturesEnabled) { if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) { ubo.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level); BindTextureMatrix(this._diffuseTexture, ubo, "diffuse"); } if (this._ambientTexture && StandardMaterial.AmbientTextureEnabled) { ubo.updateFloat2("vAmbientInfos", this._ambientTexture.coordinatesIndex, this._ambientTexture.level); BindTextureMatrix(this._ambientTexture, ubo, "ambient"); } if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) { ubo.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level); BindTextureMatrix(this._opacityTexture, ubo, "opacity"); } if (this._hasAlphaChannel()) { ubo.updateFloat("alphaCutOff", this.alphaCutOff); } BindIBLParameters(scene, defines, ubo, Color3.White(), this._reflectionTexture, false, false, true, false, false, false, this.roughness); if (!this._reflectionTexture || !StandardMaterial.ReflectionTextureEnabled) { ubo.updateFloat2("vReflectionInfos", 0.0, this.roughness); } if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) { ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level); BindTextureMatrix(this._emissiveTexture, ubo, "emissive"); } if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) { ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level); BindTextureMatrix(this._lightmapTexture, ubo, "lightmap"); } if (this._specularTexture && StandardMaterial.SpecularTextureEnabled) { ubo.updateFloat2("vSpecularInfos", this._specularTexture.coordinatesIndex, this._specularTexture.level); BindTextureMatrix(this._specularTexture, ubo, "specular"); } if (this._bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) { ubo.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, 1.0 / this._bumpTexture.level, this.parallaxScaleBias); BindTextureMatrix(this._bumpTexture, ubo, "bump"); if (scene._mirroredCameraPosition) { ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0); }