@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,052 lines (1,051 loc) • 96.8 kB
JavaScript
/** This file must only contain pure code and pure imports */
import { __esDecorate, __runInitializers } from "../tslib.es6.js";
import { serialize } from "../Misc/decorators.js";
import { Tools } from "../Misc/tools.pure.js";
import { Observable } from "../Misc/observable.pure.js";
import { EngineStore } from "../Engines/engineStore.js";
import { SubMesh } from "../Meshes/subMesh.pure.js";
import { UniformBuffer } from "./uniformBuffer.js";
import { Logger } from "../Misc/logger.js";
import { Plane } from "../Maths/math.plane.js";
import { DrawWrapper } from "./drawWrapper.js";
import { MaterialStencilState } from "./materialStencilState.js";
import { BindSceneUniformBuffer } from "./materialHelper.functions.js";
import { SerializationHelper } from "../Misc/decorators.serialization.js";
import { IsWrapper } from "./drawWrapper.functions.js";
/**
* Base class for the main features of a material in Babylon.js
*/
let Material = (() => {
var _a;
let _instanceExtraInitializers = [];
let _id_decorators;
let _id_initializers = [];
let _id_extraInitializers = [];
let _uniqueId_decorators;
let _uniqueId_initializers = [];
let _uniqueId_extraInitializers = [];
let _name_decorators;
let _name_initializers = [];
let _name_extraInitializers = [];
let _metadata_decorators;
let _metadata_initializers = [];
let _metadata_extraInitializers = [];
let _checkReadyOnEveryCall_decorators;
let _checkReadyOnEveryCall_initializers = [];
let _checkReadyOnEveryCall_extraInitializers = [];
let _checkReadyOnlyOnce_decorators;
let _checkReadyOnlyOnce_initializers = [];
let _checkReadyOnlyOnce_extraInitializers = [];
let _state_decorators;
let _state_initializers = [];
let _state_extraInitializers = [];
let __alpha_decorators;
let __alpha_initializers = [];
let __alpha_extraInitializers = [];
let __backFaceCulling_decorators;
let __backFaceCulling_initializers = [];
let __backFaceCulling_extraInitializers = [];
let __textureRepetitionMode_decorators;
let __textureRepetitionMode_initializers = [];
let __textureRepetitionMode_extraInitializers = [];
let _textureRepetitionHexTilingParams_decorators;
let _textureRepetitionHexTilingParams_initializers = [];
let _textureRepetitionHexTilingParams_extraInitializers = [];
let __cullBackFaces_decorators;
let __cullBackFaces_initializers = [];
let __cullBackFaces_extraInitializers = [];
let _sideOrientation_decorators;
let _sideOrientation_initializers = [];
let _sideOrientation_extraInitializers = [];
let __alphaMode_decorators;
let __alphaMode_initializers = [];
let __alphaMode_extraInitializers = [];
let __needDepthPrePass_decorators;
let __needDepthPrePass_initializers = [];
let __needDepthPrePass_extraInitializers = [];
let _disableDepthWrite_decorators;
let _disableDepthWrite_initializers = [];
let _disableDepthWrite_extraInitializers = [];
let _disableColorWrite_decorators;
let _disableColorWrite_initializers = [];
let _disableColorWrite_extraInitializers = [];
let _forceDepthWrite_decorators;
let _forceDepthWrite_initializers = [];
let _forceDepthWrite_extraInitializers = [];
let _depthFunction_decorators;
let _depthFunction_initializers = [];
let _depthFunction_extraInitializers = [];
let _separateCullingPass_decorators;
let _separateCullingPass_initializers = [];
let _separateCullingPass_extraInitializers = [];
let __fogEnabled_decorators;
let __fogEnabled_initializers = [];
let __fogEnabled_extraInitializers = [];
let _pointSize_decorators;
let _pointSize_initializers = [];
let _pointSize_extraInitializers = [];
let _zOffset_decorators;
let _zOffset_initializers = [];
let _zOffset_extraInitializers = [];
let _zOffsetUnits_decorators;
let _zOffsetUnits_initializers = [];
let _zOffsetUnits_extraInitializers = [];
let _get_pointsCloud_decorators;
let _get_fillMode_decorators;
let _get_useLogarithmicDepth_decorators;
let __isVertexOutputInvariant_decorators;
let __isVertexOutputInvariant_initializers = [];
let __isVertexOutputInvariant_extraInitializers = [];
let _get_transparencyMode_decorators;
return _a = class Material {
/**
* Tells the engine to draw geometry using vertex pulling instead of index drawing. This will automatically
* set the vertex buffers as storage buffers and make them accessible to the vertex shader (WebGPU only).
*/
get useVertexPulling() {
return this._useVertexPulling;
}
set useVertexPulling(value) {
if (this._useVertexPulling === value) {
return;
}
this._useVertexPulling = value;
this.markAsDirty(_a.MiscDirtyFlag);
}
/** @internal */
get _supportGlowLayer() {
return false;
}
/** @internal */
set _glowModeEnabled(value) {
// Do nothing here
}
/**
* Gets the shader language used in this material.
*/
get shaderLanguage() {
return this._shaderLanguage;
}
/**
* If the material can be rendered to several textures with MRT extension
*/
get canRenderToMRT() {
// By default, shaders are not compatible with MRTs
// Base classes should override that if their shader supports MRT
return false;
}
/**
* Sets the alpha value of the material
*/
set alpha(value) {
if (this._alpha === value) {
return;
}
const oldValue = this._alpha;
this._alpha = value;
// Only call dirty when there is a state change (no alpha / alpha)
if (oldValue === 1 || value === 1) {
this.markAsDirty(_a.MiscDirtyFlag + _a.PrePassDirtyFlag);
}
}
/**
* Gets the alpha value of the material
*/
get alpha() {
return this._alpha;
}
/**
* Sets the culling state (true to enable culling, false to disable)
*/
set backFaceCulling(value) {
if (this._backFaceCulling === value) {
return;
}
this._backFaceCulling = value;
this.markAsDirty(_a.TextureDirtyFlag);
}
/**
* Gets the culling state
*/
get backFaceCulling() {
return this._backFaceCulling;
}
/**
* Sets the texture repetition breaking mode.
* Use one of the undefined* values to break visible texture tiling patterns.
* Ordered by cost: NONE (1 fetch), NOISE_BLEND (3), HEX_TILING (3), TILE_RANDOMIZATION (4), VORONOI_BOMBING (9).
* Not supported on WebGL1 — the mode will be forced to NONE.
* @see https://iquilezles.org/articles/texturerepetition/
* @see https://jcgt.org/published/0011/03/05/
*/
set textureRepetitionMode(value) {
const clamped = Math.max(0, Math.min(value | 0, 4));
if (this._textureRepetitionMode === clamped) {
return;
}
this._textureRepetitionMode = clamped;
this.markAsDirty(_a.TextureDirtyFlag);
}
/**
* Gets the texture repetition breaking mode.
* @see https://iquilezles.org/articles/texturerepetition/
*/
get textureRepetitionMode() {
return this._textureRepetitionMode;
}
/**
* Sets the type of faces that should be culled (true for back faces, false for front faces)
*/
set cullBackFaces(value) {
if (this._cullBackFaces === value) {
return;
}
this._cullBackFaces = value;
this.markAsDirty(_a.TextureDirtyFlag);
}
/**
* Gets the type of faces that should be culled
*/
get cullBackFaces() {
return this._cullBackFaces;
}
/**
* Block the dirty-mechanism for this specific material
* When set to false after being true the material will be marked as dirty.
*/
get blockDirtyMechanism() {
return this._blockDirtyMechanism;
}
set blockDirtyMechanism(value) {
if (this._blockDirtyMechanism === value) {
return;
}
this._blockDirtyMechanism = value;
if (!value) {
this.markDirty();
}
}
/**
* This allows you to modify the material without marking it as dirty after every change.
* This function should be used if you need to make more than one dirty-enabling change to the material - adding a texture, setting a new fill mode and so on.
* The callback will pass the material as an argument, so you can make your changes to it.
* @param callback the callback to be executed that will update the material
*/
atomicMaterialsUpdate(callback) {
this.blockDirtyMechanism = true;
try {
callback(this);
}
finally {
this.blockDirtyMechanism = false;
}
}
/**
* Gets a boolean indicating that current material needs to register RTT
*/
get hasRenderTargetTextures() {
this._eventInfo.hasRenderTargetTextures = false;
this._callbackPluginEventHasRenderTargetTextures(this._eventInfo);
return this._eventInfo.hasRenderTargetTextures;
}
/**
* Called during a dispose event
*/
set onDispose(callback) {
if (this._onDisposeObserver) {
this.onDisposeObservable.remove(this._onDisposeObserver);
}
this._onDisposeObserver = this.onDisposeObservable.add(callback);
}
/**
* An event triggered when the material is bound
*/
get onBindObservable() {
if (!this._onBindObservable) {
this._onBindObservable = new Observable();
}
return this._onBindObservable;
}
/**
* Called during a bind event
*/
set onBind(callback) {
if (this._onBindObserver) {
this.onBindObservable.remove(this._onBindObserver);
}
this._onBindObserver = this.onBindObservable.add(callback);
}
/**
* An event triggered when the material is unbound
*/
get onUnBindObservable() {
if (!this._onUnBindObservable) {
this._onUnBindObservable = new Observable();
}
return this._onUnBindObservable;
}
/**
* An event triggered when the effect is (re)created
*/
get onEffectCreatedObservable() {
if (!this._onEffectCreatedObservable) {
this._onEffectCreatedObservable = new Observable();
}
return this._onEffectCreatedObservable;
}
/**
* Sets the value of the alpha mode.
*
* | Value | Type | Description |
* | --- | --- | --- |
* | 0 | ALPHA_DISABLE | |
* | 1 | ALPHA_ADD | Defines that alpha blending is COLOR=SRC_ALPHA * SRC + DEST, ALPHA=DEST_ALPHA |
* | 2 | ALPHA_COMBINE | Defines that alpha blending is COLOR=SRC_ALPHA * SRC + (1 - SRC_ALPHA) * DEST, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 3 | ALPHA_SUBTRACT | Defines that alpha blending is COLOR=(1 - SRC) * DEST, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 4 | ALPHA_MULTIPLY | Defines that alpha blending is COLOR=DEST * SRC, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 5 | ALPHA_MAXIMIZED | Defines that alpha blending is COLOR=SRC_ALPHA * SRC + (1 - SRC) * DEST, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 6 | ALPHA_ONEONE | Defines that alpha blending is COLOR=SRC + DEST, ALPHA=DEST_ALPHA |
* | 7 | ALPHA_PREMULTIPLIED | Defines that alpha blending is COLOR=SRC + (1 - SRC_ALPHA) * DEST, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 8 | ALPHA_PREMULTIPLIED_PORTERDUFF | Defines that alpha blending is COLOR=SRC + (1 - SRC_ALPHA) * DEST, ALPHA=SRC_ALPHA + (1 - SRC_ALPHA) * DEST_ALPHA |
* | 9 | ALPHA_INTERPOLATE | Defines that alpha blending is COLOR=CST * SRC + (1 - CST) * DEST, ALPHA=CST_ALPHA * SRC + (1 - CST_ALPHA) * DEST_ALPHA |
* | 10 | ALPHA_SCREENMODE | Defines that alpha blending is COLOR=SRC + (1 - SRC) * DEST, ALPHA=SRC_ALPHA + (1 - SRC_ALPHA) * DEST_ALPHA |
* | 11 | ALPHA_ONEONE_ONEONE | Defines that alpha blending is COLOR=SRC + DST, ALPHA=SRC_ALPHA + DEST_ALPHA |
* | 12 | ALPHA_ALPHATOCOLOR | Defines that alpha blending is COLOR=DEST_ALPHA * SRC + DST, ALPHA=0 |
* | 13 | ALPHA_REVERSEONEMINUS | Defines that alpha blending is COLOR=(1 - DEST) * SRC + (1 - SRC) * DEST, ALPHA=(1 - DEST_ALPHA) * SRC_ALPHA + (1 - SRC_ALPHA) * DEST_ALPHA |
* | 14 | ALPHA_SRC_DSTONEMINUSSRCALPHA | Defines that alpha blending is ALPHA=SRC + (1 - SRC ALPHA) * DEST, ALPHA=SRC_ALPHA + (1 - SRC ALPHA) * DEST_ALPHA |
* | 15 | ALPHA_ONEONE_ONEZERO | Defines that alpha blending is COLOR=SRC + DST, ALPHA=SRC_ALPHA |
* | 16 | ALPHA_EXCLUSION | Defines that alpha blending is COLOR=(1 - DEST) * SRC + (1 - SRC) * DEST, ALPHA=DEST_ALPHA |
* | 17 | ALPHA_LAYER_ACCUMULATE | Defines that alpha blending is COLOR=SRC_ALPHA * SRC + (1 - SRC ALPHA) * DEST, ALPHA=SRC_ALPHA + (1 - SRC_ALPHA) * DEST_ALPHA |
* | 18 | ALPHA_MIN | Defines that alpha blending is COLOR=MIN(SRC, DEST), ALPHA=MIN(SRC_ALPHA, DEST_ALPHA) |
* | 19 | ALPHA_MAX | Defines that alpha blending is COLOR=MAX(SRC, DEST), ALPHA=MAX(SRC_ALPHA, DEST_ALPHA) |
* | 20 | ALPHA_DUAL_SRC0_ADD_SRC1xDST | Defines that alpha blending uses dual source blending and is COLOR=SRC + SRC1 * DEST, ALPHA=DST_ALPHA |
* | 21 | ALPHA_REPLACE_COLOR | Defines that alpha blending is COLOR=SRC, ALPHA=SRC_ALPHA + (1 - SRC_ALPHA) * DEST_ALPHA |
*
*/
set alphaMode(value) {
if (this._alphaMode[0] === value) {
return;
}
this._alphaMode[0] = value;
this.markAsDirty(_a.TextureDirtyFlag);
}
/**
* Gets the value of the alpha mode
*/
get alphaMode() {
return this._alphaMode[0];
}
/**
* Gets the list of alpha modes (length greater than 1 for multi-targets)
*/
get alphaModes() {
return this._alphaMode;
}
/**
* Sets the value of the alpha mode for a specific target index.
* @param value The alpha mode value to set.
* @param targetIndex The index of the target to set the alpha mode for. Defaults to 0.
*/
setAlphaMode(value, targetIndex = 0) {
if (this._alphaMode[targetIndex] === value) {
return;
}
this._alphaMode[targetIndex] = value;
this.markAsDirty(_a.TextureDirtyFlag);
}
/**
* Sets the need depth pre-pass value
*/
set needDepthPrePass(value) {
if (this._needDepthPrePass === value) {
return;
}
this._needDepthPrePass = value;
if (this._needDepthPrePass) {
this.checkReadyOnEveryCall = true;
}
}
/**
* Gets the depth pre-pass value
*/
get needDepthPrePass() {
return this._needDepthPrePass;
}
/**
* Can this material render to prepass
*/
get isPrePassCapable() {
return false;
}
/**
* Sets the state for enabling fog
*/
set fogEnabled(value) {
if (this._fogEnabled === value) {
return;
}
this._fogEnabled = value;
this.markAsDirty(_a.MiscDirtyFlag);
}
/**
* Gets the value of the fog enabled state
*/
get fogEnabled() {
return this._fogEnabled;
}
get wireframe() {
switch (this._fillMode) {
case _a.WireFrameFillMode:
case _a.LineListDrawMode:
case _a.LineLoopDrawMode:
case _a.LineStripDrawMode:
return true;
}
return this._scene.forceWireframe;
}
/**
* Sets the state of wireframe mode
*/
set wireframe(value) {
this.fillMode = value ? _a.WireFrameFillMode : _a.TriangleFillMode;
}
/**
* Gets the value specifying if point clouds are enabled
*/
get pointsCloud() {
switch (this._fillMode) {
case _a.PointFillMode:
case _a.PointListDrawMode:
return true;
}
return this._scene.forcePointsCloud;
}
/**
* Sets the state of point cloud mode
*/
set pointsCloud(value) {
this.fillMode = value ? _a.PointFillMode : _a.TriangleFillMode;
}
/**
* Gets the material fill mode
*/
get fillMode() {
return this._fillMode;
}
/**
* Sets the material fill mode
*/
set fillMode(value) {
if (this._fillMode === value) {
return;
}
this._fillMode = value;
this.markAsDirty(_a.MiscDirtyFlag);
}
/**
* In case the depth buffer does not allow enough depth precision for your scene (might be the case in large scenes)
* You can try switching to logarithmic depth.
* @see https://doc.babylonjs.com/features/featuresDeepDive/materials/advanced/logarithmicDepthBuffer
*/
get useLogarithmicDepth() {
return this._useLogarithmicDepth;
}
set useLogarithmicDepth(value) {
const fragmentDepthSupported = this.getScene().getEngine().getCaps().fragmentDepthSupported;
if (value && !fragmentDepthSupported) {
Logger.Warn("Logarithmic depth has been requested for a material on a device that doesn't support it.");
}
this._useLogarithmicDepth = value && fragmentDepthSupported;
this._markAllSubMeshesAsMiscDirty();
}
/**
* Gets or sets the vertex output invariant state
* Setting this property to true will force the shader compiler to disable some optimization to make sure the vertex output is always calculated
* the same way across different compilation units.
* You may need to enable this option if you are seeing some depth artifacts when using a depth pre-pass, for e.g.
* Note that this may have an impact on performance, so leave this option disabled if not needed.
*/
get isVertexOutputInvariant() {
return this._isVertexOutputInvariant;
}
set isVertexOutputInvariant(value) {
if (this._isVertexOutputInvariant === value) {
return;
}
this._isVertexOutputInvariant = value;
this._markAllSubMeshesAsMiscDirty();
}
/** @internal */
_getDrawWrapper() {
return this._drawWrapper;
}
/**
* @internal
*/
_setDrawWrapper(drawWrapper) {
this._drawWrapper = drawWrapper;
}
/**
* Creates a material instance
* @param name defines the name of the material
* @param scene defines the scene to reference
* @param doNotAdd specifies if the material should be added to the scene
* @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false
*/
constructor(name, scene, doNotAdd, forceGLSL = false) {
/**
* Custom callback helping to override the default shader used in the material.
*/
this.customShaderNameResolve = __runInitializers(this, _instanceExtraInitializers);
/**
* Custom shadow depth material to use for shadow rendering instead of the in-built one
*/
this.shadowDepthWrapper = null;
/**
* Gets or sets a boolean indicating that the material is allowed (if supported) to do shader hot swapping.
* This means that the material can keep using a previous shader while a new one is being compiled.
* This is mostly used when shader parallel compilation is supported (true by default)
*/
this.allowShaderHotSwapping = true;
/** Shader language used by the material */
this._shaderLanguage = 0 /* ShaderLanguage.GLSL */;
this._forceGLSL = false;
this._useVertexPulling = false;
/**
* The ID of the material
*/
this.id = __runInitializers(this, _id_initializers, void 0);
/**
* Gets or sets the unique id of the material
*/
this.uniqueId = (__runInitializers(this, _id_extraInitializers), __runInitializers(this, _uniqueId_initializers, void 0));
/** @internal */
this._loadedUniqueId = __runInitializers(this, _uniqueId_extraInitializers);
/**
* The name of the material
*/
this.name = __runInitializers(this, _name_initializers, void 0);
/**
* Gets or sets user defined metadata
*/
this.metadata = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _metadata_initializers, null));
/** @internal */
this._internalMetadata = __runInitializers(this, _metadata_extraInitializers);
/**
* For internal use only. Please do not use.
*/
this.reservedDataStore = null;
/**
* Specifies if the ready state should be checked on each call
*/
this.checkReadyOnEveryCall = __runInitializers(this, _checkReadyOnEveryCall_initializers, false);
/**
* Specifies if the ready state should be checked once
*/
this.checkReadyOnlyOnce = (__runInitializers(this, _checkReadyOnEveryCall_extraInitializers), __runInitializers(this, _checkReadyOnlyOnce_initializers, false));
/**
* The state of the material
*/
this.state = (__runInitializers(this, _checkReadyOnlyOnce_extraInitializers), __runInitializers(this, _state_initializers, ""));
/**
* The alpha value of the material
*/
this._alpha = (__runInitializers(this, _state_extraInitializers), __runInitializers(this, __alpha_initializers, 1.0));
/**
* List of inspectable custom properties (used by the Inspector)
* @see https://doc.babylonjs.com/toolsAndResources/inspector#extensibility
*/
this.inspectableCustomProperties = __runInitializers(this, __alpha_extraInitializers);
/**
* Specifies if back face culling is enabled
*/
this._backFaceCulling = __runInitializers(this, __backFaceCulling_initializers, true);
this._textureRepetitionMode = (__runInitializers(this, __backFaceCulling_extraInitializers), __runInitializers(this, __textureRepetitionMode_initializers, 0));
/**
* Parameters for the hex tiling texture repetition mode (TEXTURE_REPETITION_HEX_TILING).
* x = rotation strength (0..1, default 1.0) — how much each hex tile is rotated.
* y = fall-off contrast (0..1, default 0.6) — how much luminance affects blending weight at tile borders.
* z = exponent (1..20, default 7.0) — controls the sharpness of weight falloff between tiles.
* w = contrast (0..1, default 0.5) — boost blending contrast via Gain3 (0.5 = neutral, >0.5 = higher contrast).
* @see https://jcgt.org/published/0011/03/05/
*/
this.textureRepetitionHexTilingParams = (__runInitializers(this, __textureRepetitionMode_extraInitializers), __runInitializers(this, _textureRepetitionHexTilingParams_initializers, [1.0, 0.6, 7.0, 0.5]));
/**
* Specifies if back or front faces should be culled (when culling is enabled)
*/
this._cullBackFaces = (__runInitializers(this, _textureRepetitionHexTilingParams_extraInitializers), __runInitializers(this, __cullBackFaces_initializers, true));
this._blockDirtyMechanism = (__runInitializers(this, __cullBackFaces_extraInitializers), false);
/**
* Stores the value for side orientation
*/
this.sideOrientation = __runInitializers(this, _sideOrientation_initializers, null);
/**
* Callback triggered when the material is compiled
*/
this.onCompiled = (__runInitializers(this, _sideOrientation_extraInitializers), null);
/**
* Callback triggered when an error occurs
*/
this.onError = null;
/**
* Callback triggered to get the render target textures
*/
this.getRenderTargetTextures = null;
/**
* Specifies if the material should be serialized
*/
this.doNotSerialize = false;
/**
* @internal
*/
this._storeEffectOnSubMeshes = false;
/**
* Stores the animations for the material
*/
this.animations = null;
/**
* An event triggered when the material is disposed
*/
this.onDisposeObservable = new Observable();
/**
* An observer which watches for dispose events
*/
this._onDisposeObserver = null;
this._onUnBindObservable = null;
/**
* An observer which watches for bind events
*/
this._onBindObserver = null;
/**
* Stores the value of the alpha mode
*/
this._alphaMode = __runInitializers(this, __alphaMode_initializers, [2]);
/**
* Stores the state of the need depth pre-pass value
*/
this._needDepthPrePass = (__runInitializers(this, __alphaMode_extraInitializers), __runInitializers(this, __needDepthPrePass_initializers, false));
/**
* Specifies if depth writing should be disabled
*/
this.disableDepthWrite = (__runInitializers(this, __needDepthPrePass_extraInitializers), __runInitializers(this, _disableDepthWrite_initializers, false));
/**
* Specifies if color writing should be disabled
*/
this.disableColorWrite = (__runInitializers(this, _disableDepthWrite_extraInitializers), __runInitializers(this, _disableColorWrite_initializers, false));
/**
* Specifies if depth writing should be forced
*/
this.forceDepthWrite = (__runInitializers(this, _disableColorWrite_extraInitializers), __runInitializers(this, _forceDepthWrite_initializers, false));
/**
* Specifies the depth function that should be used. 0 means the default engine function
*/
this.depthFunction = (__runInitializers(this, _forceDepthWrite_extraInitializers), __runInitializers(this, _depthFunction_initializers, 0));
/**
* Specifies if there should be a separate pass for culling
*/
this.separateCullingPass = (__runInitializers(this, _depthFunction_extraInitializers), __runInitializers(this, _separateCullingPass_initializers, false));
/**
* Stores the state specifying if fog should be enabled
*/
this._fogEnabled = (__runInitializers(this, _separateCullingPass_extraInitializers), __runInitializers(this, __fogEnabled_initializers, true));
/**
* Stores the size of points
*/
this.pointSize = (__runInitializers(this, __fogEnabled_extraInitializers), __runInitializers(this, _pointSize_initializers, 1.0));
/**
* Stores the z offset Factor value
*/
this.zOffset = (__runInitializers(this, _pointSize_extraInitializers), __runInitializers(this, _zOffset_initializers, 0));
/**
* Stores the z offset Units value
*/
this.zOffsetUnits = (__runInitializers(this, _zOffset_extraInitializers), __runInitializers(this, _zOffsetUnits_initializers, 0));
/**
* Gets or sets the active clipplane 1
*/
this.clipPlane = __runInitializers(this, _zOffsetUnits_extraInitializers);
/**
* Gives access to the stencil properties of the material
*/
this.stencil = new MaterialStencilState();
this._isVertexOutputInvariant = __runInitializers(this, __isVertexOutputInvariant_initializers, _a.ForceVertexOutputInvariant);
/**
* @internal
* Stores the effects for the material
*/
this._materialContext = __runInitializers(this, __isVertexOutputInvariant_extraInitializers);
/**
* Specifies if uniform buffers should be used
*/
this._useUBO = false;
/**
* Stores the fill mode state
*/
this._fillMode = _a.TriangleFillMode;
/**
* Specifies if the depth write state should be cached
*/
this._cachedDepthWriteState = false;
/**
* Specifies if the color write state should be cached
*/
this._cachedColorWriteState = false;
/**
* Specifies if the depth function state should be cached
*/
this._cachedDepthFunctionState = 0;
/** @internal */
this._indexInSceneMaterialArray = -1;
/** @internal */
this.meshMap = null;
/** @internal */
this._parentContainer = null;
/** @internal */
this._uniformBufferLayoutBuilt = false;
this._eventInfo = {}; // will be initialized before each event notification
/** @internal */
this._callbackPluginEventGeneric = () => void 0;
/** @internal */
this._callbackPluginEventIsReadyForSubMesh = () => void 0;
/** @internal */
this._callbackPluginEventPrepareDefines = () => void 0;
/** @internal */
this._callbackPluginEventPrepareDefinesBeforeAttributes = () => void 0;
/** @internal */
this._callbackPluginEventHardBindForSubMesh = () => void 0;
/** @internal */
this._callbackPluginEventBindForSubMesh = () => void 0;
/** @internal */
this._callbackPluginEventHasRenderTargetTextures = () => void 0;
/** @internal */
this._callbackPluginEventFillRenderTargetTextures = () => void 0;
/**
* The transparency mode of the material.
*/
this._transparencyMode = null;
this.name = name;
const setScene = scene || EngineStore.LastCreatedScene;
if (!setScene) {
return;
}
this._scene = setScene;
this._dirtyCallbacks = {};
this._forceGLSL = forceGLSL;
this._dirtyCallbacks[1] = this._markAllSubMeshesAsTexturesDirty.bind(this);
this._dirtyCallbacks[2] = this._markAllSubMeshesAsLightsDirty.bind(this);
this._dirtyCallbacks[4] = this._markAllSubMeshesAsFresnelDirty.bind(this);
this._dirtyCallbacks[8] = this._markAllSubMeshesAsAttributesDirty.bind(this);
this._dirtyCallbacks[16] = this._markAllSubMeshesAsMiscDirty.bind(this);
this._dirtyCallbacks[32] = this._markAllSubMeshesAsPrePassDirty.bind(this);
this._dirtyCallbacks[127] = this._markAllSubMeshesAsAllDirty.bind(this);
this.id = name || Tools.RandomId();
this.uniqueId = this._scene.getUniqueId();
this._materialContext = this._scene.getEngine().createMaterialContext();
this._drawWrapper = new DrawWrapper(this._scene.getEngine(), false);
this._drawWrapper.materialContext = this._materialContext;
this._uniformBuffer = new UniformBuffer(this._scene.getEngine(), undefined, undefined, name);
this._useUBO = this.getScene().getEngine().supportsUniformBuffers;
this._createUniformBuffer();
if (!doNotAdd) {
this._scene.addMaterial(this);
}
if (this._scene.useMaterialMeshMap) {
this.meshMap = {};
}
_a.OnEventObservable.notifyObservers(this, 1 /* MaterialPluginEvent.Created */);
}
/** @internal */
_createUniformBuffer() {
const engine = this.getScene().getEngine();
this._uniformBuffer?.dispose();
if (engine.isWebGPU && !this._forceGLSL) {
// Switch main UBO to non UBO to connect to leftovers UBO in webgpu
this._uniformBuffer = new UniformBuffer(engine, undefined, undefined, this.name, true);
this._shaderLanguage = 1 /* ShaderLanguage.WGSL */;
}
else {
this._uniformBuffer = new UniformBuffer(this._scene.getEngine(), undefined, undefined, this.name);
}
this._uniformBufferLayoutBuilt = false;
}
/**
* Returns a string representation of the current material
* @param fullDetails defines a boolean indicating which levels of logging is desired
* @returns a string with material information
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
toString(fullDetails) {
const ret = "Name: " + this.name;
return ret;
}
/**
* Gets the class name of the material
* @returns a string with the class name of the material
*/
getClassName() {
return "Material";
}
/** @internal */
get _isMaterial() {
return true;
}
/**
* Specifies if updates for the material been locked
*/
get isFrozen() {
return this.checkReadyOnlyOnce;
}
/**
* Locks updates for the material.
*
* Note: while a material is frozen, the scene can still rebind it at least
* once per camera render (and again whenever another material was bound in
* between). What can be skipped while the frozen material stays cached are
* per-mesh updates performed during a rebind.
*
* This includes per-mesh morph target influences. If the same frozen
* material is shared across several meshes that each have different
* per-mesh morph influences, only the mesh that triggers the rebind updates
* those values. Other meshes rendered afterward with the same cached frozen
* material may reuse stale influences and render with the wrong values.
*
* For that scenario either keep the material unfrozen, clone the material
* per mesh and freeze each clone, or `unfreeze()` before changing
* influences and `freeze()` again afterwards.
*/
freeze() {
this.markDirty();
this.checkReadyOnlyOnce = true;
}
/**
* Unlocks updates for the material
*/
unfreeze() {
this.markDirty();
this.checkReadyOnlyOnce = false;
}
/**
* Specifies if the material is ready to be used
* @param mesh defines the mesh to check
* @param useInstances specifies if instances should be used
* @returns a boolean indicating if the material is ready to be used
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isReady(mesh, useInstances) {
return true;
}
/**
* Specifies that the submesh is ready to be used
* @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
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isReadyForSubMesh(mesh, subMesh, useInstances) {
const defines = subMesh.materialDefines;
if (!defines) {
return false;
}
this._eventInfo.isReadyForSubMesh = true;
this._eventInfo.defines = defines;
this._callbackPluginEventIsReadyForSubMesh(this._eventInfo);
return this._eventInfo.isReadyForSubMesh;
}
/**
* Returns the material effect
* @returns the effect associated with the material
*/
getEffect() {
return this._drawWrapper.effect;
}
/**
* Returns the current scene
* @returns a Scene
*/
getScene() {
return this._scene;
}
/** @internal */
_getEffectiveOrientation(mesh) {
return this.sideOrientation !== null ? this.sideOrientation : mesh.sideOrientation;
}
/**
* Gets the current transparency mode.
*/
get transparencyMode() {
return this._transparencyMode;
}
/**
* Sets the transparency mode of the material.
*
* | Value | Type | Description |
* | ----- | ----------------------------------- | ----------- |
* | 0 | OPAQUE | |
* | 1 | ALPHATEST | |
* | 2 | ALPHABLEND | |
* | 3 | ALPHATESTANDBLEND | |
*
*/
set transparencyMode(value) {
if (this._transparencyMode === value) {
return;
}
this._transparencyMode = value;
this._markAllSubMeshesAsTexturesAndMiscDirty();
}
get _hasTransparencyMode() {
return this._transparencyMode != null;
}
get _transparencyModeIsBlend() {
return this._transparencyMode === _a.MATERIAL_ALPHABLEND || this._transparencyMode === _a.MATERIAL_ALPHATESTANDBLEND;
}
get _transparencyModeIsTest() {
return this._transparencyMode === _a.MATERIAL_ALPHATEST || this._transparencyMode === _a.MATERIAL_ALPHATESTANDBLEND;
}
/**
* Returns true if alpha blending should be disabled.
*/
get _disableAlphaBlending() {
return this._transparencyMode === _a.MATERIAL_OPAQUE || this._transparencyMode === _a.MATERIAL_ALPHATEST;
}
/**
* Specifies whether or not this material should be rendered in alpha blend mode.
* @returns a boolean specifying if alpha blending is needed
* @deprecated Please use needAlphaBlendingForMesh instead
*/
needAlphaBlending() {
if (this._hasTransparencyMode) {
return this._transparencyModeIsBlend;
}
if (this._disableAlphaBlending) {
return false;
}
return this.alpha < 1.0;
}
/**
* Specifies if the mesh will require alpha blending
* @param mesh defines the mesh to check
* @returns a boolean specifying if alpha blending is needed for the mesh
*/
needAlphaBlendingForMesh(mesh) {
if (this._hasTransparencyMode) {
return this._transparencyModeIsBlend;
}
if (mesh.visibility < 1.0) {
return true;
}
if (this._disableAlphaBlending) {
return false;
}
return mesh.hasVertexAlpha || this.needAlphaBlending();
}
/**
* Specifies whether or not this material should be rendered in alpha test mode.
* @returns a boolean specifying if an alpha test is needed.
* @deprecated Please use needAlphaTestingForMesh instead
*/
needAlphaTesting() {
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}
return false;
}
/**
* Specifies if material alpha testing should be turned on for the mesh
* @param mesh defines the mesh to check
* @returns a boolean specifying if alpha testing should be turned on for the mesh
*/
needAlphaTestingForMesh(mesh) {
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}
return !this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting();
}
/**
* Gets the texture used for the alpha test
* @returns the texture to use for alpha testing
*/
getAlphaTestTexture() {
return null;
}
/**
* Marks the material to indicate that it needs to be re-calculated
* @param forceMaterialDirty - Forces the material to be marked as dirty for all components (same as this.markAsDirty(Material.AllDirtyFlag)). You should use this flag if the material is frozen and you want to force a recompilation.
*/
markDirty(forceMaterialDirty = false) {
const meshes = this.getScene().meshes;
for (const mesh of meshes) {
if (!mesh.subMeshes) {
continue;
}
for (const subMesh of mesh.subMeshes) {
if (subMesh.getMaterial() !== this) {
continue;
}
for (const drawWrapper of subMesh._drawWrappers) {
if (!drawWrapper) {
continue;
}
if (this._materialContext === drawWrapper.materialContext) {
drawWrapper._wasPreviouslyReady = false;
drawWrapper._wasPreviouslyUsingInstances = null;
drawWrapper._forceRebindOnNextCall = forceMaterialDirty;
}
}
}
}
if (forceMaterialDirty) {
this.markAsDirty(_a.AllDirtyFlag);
}
}
/**
* @internal
*/
_preBind(effect, overrideOrientation = null) {
const engine = this._scene.getEngine();
const orientation = overrideOrientation == null ? this.sideOrientation : overrideOrientation;
const reverse = orientation === _a.ClockWiseSideOrientation;
const effectiveDrawWrapper = effect ? effect : this._getDrawWrapper();
if (IsWrapper(effectiveDrawWrapper) && effectiveDrawWrapper.materialContext) {
effectiveDrawWrapper.materialContext.useVertexPulling = this.useVertexPulling;
}
engine.enableEffect(effectiveDrawWrapper);
engine.setState(this.backFaceCulling, this.zOffset, false, reverse, this._scene._mirroredCameraPosition ? !this.cullBackFaces : this.cullBackFaces, this.stencil, this.zOffsetUnits);
return reverse;
}
/**
* Binds the material to the mesh
* @param world defines the world transformation matrix
* @param mesh defines the mesh to bind the material to
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
bind(world, mesh) { }
/**
* Initializes the uniform buffer layout for the shader.
*/
buildUniformLayout() {
const ubo = this._uniformBuffer;
this._eventInfo.ubo = ubo;
this._callbackPluginEventGeneric(8 /* MaterialPluginEvent.PrepareUniformBuffer */, this._eventInfo);
ubo.create();
this._uniformBufferLayoutBuilt = true;
}
/**
* Binds the submesh to the material
* @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 drawWrapper = subMesh._drawWrapper;
this._eventInfo.subMesh = subMesh;
this._callbackPluginEventBindForSubMesh(this._eventInfo);
drawWrapper._forceRebindOnNextCall = false;
}
/**
* Binds the world matrix to the material
* @param world defines the world transformation matrix
*/
// eslint-disabl