@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.
803 lines (802 loc) • 34.3 kB
JavaScript
import { Observable } from "../Misc/observable.js";
import { Color4 } from "../Maths/math.color.js";
import { EngineStore } from "../Engines/engineStore.js";
import { VertexBuffer } from "../Buffers/buffer.js";
import { EffectWrapper } from "../Materials/effectRenderer.js";
import { Material } from "../Materials/material.js";
import { EffectFallbacks } from "../Materials/effectFallbacks.js";
import { DrawWrapper } from "../Materials/drawWrapper.js";
import { AddClipPlaneUniforms, BindClipPlane, PrepareStringDefinesForClipPlanes } from "../Materials/clipPlaneMaterialHelper.js";
import { BindMorphTargetParameters, PrepareDefinesAndAttributesForMorphTargets, PushAttributesForInstances } from "../Materials/materialHelper.functions.js";
import { ObjectRenderer } from "../Rendering/objectRenderer.js";
import { Engine } from "../Engines/engine.js";
/**
* Special Glow Blur post process only blurring the alpha channel
* It enforces keeping the most luminous color in the color channel.
* @internal
*/
export class ThinGlowBlurPostProcess extends EffectWrapper {
constructor(name, engine = null, direction, kernel, options) {
super({
...options,
name,
engine: engine || Engine.LastCreatedEngine,
useShaderStore: true,
useAsPostProcess: true,
fragmentShader: ThinGlowBlurPostProcess.FragmentUrl,
uniforms: ThinGlowBlurPostProcess.Uniforms,
});
this.direction = direction;
this.kernel = kernel;
this.textureWidth = 0;
this.textureHeight = 0;
}
_gatherImports(useWebGPU, list) {
if (useWebGPU) {
this._webGPUReady = true;
list.push(import("../ShadersWGSL/glowBlurPostProcess.fragment.js"));
}
else {
list.push(import("../Shaders/glowBlurPostProcess.fragment.js"));
}
super._gatherImports(useWebGPU, list);
}
bind() {
super.bind();
this._drawWrapper.effect.setFloat2("screenSize", this.textureWidth, this.textureHeight);
this._drawWrapper.effect.setVector2("direction", this.direction);
this._drawWrapper.effect.setFloat("blurWidth", this.kernel);
}
}
/**
* The fragment shader url
*/
ThinGlowBlurPostProcess.FragmentUrl = "glowBlurPostProcess";
/**
* The list of uniforms used by the effect
*/
ThinGlowBlurPostProcess.Uniforms = ["screenSize", "direction", "blurWidth"];
/**
* @internal
*/
export class ThinEffectLayer {
/**
* Gets/sets the camera attached to the layer.
*/
get camera() {
return this._options.camera;
}
set camera(camera) {
this._options.camera = camera;
}
/**
* Gets the rendering group id the layer should render in.
*/
get renderingGroupId() {
return this._options.renderingGroupId;
}
set renderingGroupId(renderingGroupId) {
this._options.renderingGroupId = renderingGroupId;
}
/**
* Gets the object renderer used to render objects in the layer
*/
get objectRenderer() {
return this._objectRenderer;
}
/**
* Gets the shader language used in this material.
*/
get shaderLanguage() {
return this._shaderLanguage;
}
/**
* Sets a specific material to be used to render a mesh/a list of meshes in the layer
* @param mesh mesh or array of meshes
* @param material material to use by the layer when rendering the mesh(es). If undefined is passed, the specific material created by the layer will be used.
*/
setMaterialForRendering(mesh, material) {
this._objectRenderer.setMaterialForRendering(mesh, material);
if (Array.isArray(mesh)) {
for (let i = 0; i < mesh.length; ++i) {
const currentMesh = mesh[i];
if (!material) {
delete this._materialForRendering[currentMesh.uniqueId];
}
else {
this._materialForRendering[currentMesh.uniqueId] = [currentMesh, material];
}
}
}
else {
if (!material) {
delete this._materialForRendering[mesh.uniqueId];
}
else {
this._materialForRendering[mesh.uniqueId] = [mesh, material];
}
}
}
/**
* Gets the intensity of the effect for a specific mesh.
* @param mesh The mesh to get the effect intensity for
* @returns The intensity of the effect for the mesh
*/
getEffectIntensity(mesh) {
return this._effectIntensity[mesh.uniqueId] ?? 1;
}
/**
* Sets the intensity of the effect for a specific mesh.
* @param mesh The mesh to set the effect intensity for
* @param intensity The intensity of the effect for the mesh
*/
setEffectIntensity(mesh, intensity) {
this._effectIntensity[mesh.uniqueId] = intensity;
}
/**
* Instantiates a new effect Layer
* @param name The name of the layer
* @param scene The scene to use the layer in
* @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false
* @param dontCheckIfReady Specifies if the layer should disable checking whether all the post processes are ready (default: false). To save performance, this should be set to true and you should call `isReady` manually before rendering to the layer.
* @param _additionalImportShadersAsync Additional shaders to import when the layer is created
*/
constructor(name, scene, forceGLSL = false, dontCheckIfReady = false, _additionalImportShadersAsync) {
this._additionalImportShadersAsync = _additionalImportShadersAsync;
this._vertexBuffers = {};
this._dontCheckIfReady = false;
/** @internal */
this._shouldRender = true;
/** @internal */
this._emissiveTextureAndColor = { texture: null, color: new Color4() };
/** @internal */
this._effectIntensity = {};
/** @internal */
this._postProcesses = [];
/**
* The clear color of the texture used to generate the glow map.
*/
this.neutralColor = new Color4();
/**
* Specifies whether the effect layer is enabled or not.
*/
this.isEnabled = true;
/**
* Specifies if the bounding boxes should be rendered normally or if they should undergo the effect of the layer
*/
this.disableBoundingBoxesFromEffectLayer = false;
/**
* An event triggered when the effect layer has been disposed.
*/
this.onDisposeObservable = new Observable();
/**
* An event triggered when the effect layer is about rendering the main texture with the glowy parts.
*/
this.onBeforeRenderLayerObservable = new Observable();
/**
* An event triggered when the generated texture is being merged in the scene.
*/
this.onBeforeComposeObservable = new Observable();
/**
* An event triggered when the mesh is rendered into the effect render target.
*/
this.onBeforeRenderMeshToEffect = new Observable();
/**
* An event triggered after the mesh has been rendered into the effect render target.
*/
this.onAfterRenderMeshToEffect = new Observable();
/**
* An event triggered when the generated texture has been merged in the scene.
*/
this.onAfterComposeObservable = new Observable();
/**
* An event triggered when the layer is being blurred.
*/
this.onBeforeBlurObservable = new Observable();
/**
* An event triggered when the layer has been blurred.
*/
this.onAfterBlurObservable = new Observable();
this._shaderLanguage = 0 /* ShaderLanguage.GLSL */;
this._materialForRendering = {};
/** @internal */
this._shadersLoaded = false;
this.name = name;
this._scene = scene || EngineStore.LastCreatedScene;
this._dontCheckIfReady = dontCheckIfReady;
const engine = this._scene.getEngine();
if (engine.isWebGPU && !forceGLSL && !ThinEffectLayer.ForceGLSL) {
this._shaderLanguage = 1 /* ShaderLanguage.WGSL */;
}
this._engine = this._scene.getEngine();
this._mergeDrawWrapper = [];
// Generate Buffers
this._generateIndexBuffer();
this._generateVertexBuffer();
}
/**
* Get the effect name of the layer.
* @returns The effect name
*/
getEffectName() {
return "";
}
/**
* Checks for the readiness of the element composing the layer.
* @param _subMesh the mesh to check for
* @param _useInstances specify whether or not to use instances to render the mesh
* @returns true if ready otherwise, false
*/
isReady(_subMesh, _useInstances) {
return true;
}
/**
* Returns whether or not the layer needs stencil enabled during the mesh rendering.
* @returns true if the effect requires stencil during the main canvas render pass.
*/
needStencil() {
return false;
}
/** @internal */
_createMergeEffect() {
throw new Error("Effect Layer: no merge effect defined");
}
/** @internal */
_createTextureAndPostProcesses() { }
/** @internal */
_internalCompose(_effect, _renderIndex) { }
/** @internal */
_setEmissiveTextureAndColor(_mesh, _subMesh, _material) { }
/** @internal */
_numInternalDraws() {
return 1;
}
/** @internal */
_init(options) {
// Adapt options
this._options = {
mainTextureRatio: 0.5,
mainTextureFixedSize: 0,
mainTextureType: 0,
alphaBlendingMode: 2,
camera: null,
renderingGroupId: -1,
...options,
};
this._createObjectRenderer();
}
_generateIndexBuffer() {
// Indices
const indices = [];
indices.push(0);
indices.push(1);
indices.push(2);
indices.push(0);
indices.push(2);
indices.push(3);
this._indexBuffer = this._engine.createIndexBuffer(indices);
}
_generateVertexBuffer() {
// VBO
const vertices = [];
vertices.push(1, 1);
vertices.push(-1, 1);
vertices.push(-1, -1);
vertices.push(1, -1);
const vertexBuffer = new VertexBuffer(this._engine, vertices, VertexBuffer.PositionKind, false, false, 2);
this._vertexBuffers[VertexBuffer.PositionKind] = vertexBuffer;
}
_createObjectRenderer() {
this._objectRenderer = new ObjectRenderer(`ObjectRenderer for thin effect layer ${this.name}`, this._scene, {
doNotChangeAspectRatio: true,
});
this._objectRenderer.activeCamera = this._options.camera;
this._objectRenderer.renderParticles = false;
this._objectRenderer.renderList = null;
// Prevent package size in es6 (getBoundingBoxRenderer might not be present)
const hasBoundingBoxRenderer = !!this._scene.getBoundingBoxRenderer;
let boundingBoxRendererEnabled = false;
if (hasBoundingBoxRenderer) {
this._objectRenderer.onBeforeRenderObservable.add(() => {
boundingBoxRendererEnabled = this._scene.getBoundingBoxRenderer().enabled;
this._scene.getBoundingBoxRenderer().enabled = !this.disableBoundingBoxesFromEffectLayer && boundingBoxRendererEnabled;
});
this._objectRenderer.onAfterRenderObservable.add(() => {
this._scene.getBoundingBoxRenderer().enabled = boundingBoxRendererEnabled;
});
}
this._objectRenderer.customIsReadyFunction = (mesh, refreshRate, preWarm) => {
if ((preWarm || refreshRate === 0) && mesh.subMeshes) {
for (let i = 0; i < mesh.subMeshes.length; ++i) {
const subMesh = mesh.subMeshes[i];
const material = subMesh.getMaterial();
const renderingMesh = subMesh.getRenderingMesh();
if (!material) {
continue;
}
const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
const hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id] || renderingMesh.hasThinInstances;
this._setEmissiveTextureAndColor(renderingMesh, subMesh, material);
if (!this._isSubMeshReady(subMesh, hardwareInstancedRendering, this._emissiveTextureAndColor.texture)) {
return false;
}
}
}
return true;
};
// Custom render function
this._objectRenderer.customRenderFunction = (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, depthOnlySubMeshes) => {
this.onBeforeRenderLayerObservable.notifyObservers(this);
let index;
const engine = this._scene.getEngine();
if (depthOnlySubMeshes.length) {
engine.setColorWrite(false);
for (index = 0; index < depthOnlySubMeshes.length; index++) {
this._renderSubMesh(depthOnlySubMeshes.data[index]);
}
engine.setColorWrite(true);
}
for (index = 0; index < opaqueSubMeshes.length; index++) {
this._renderSubMesh(opaqueSubMeshes.data[index]);
}
for (index = 0; index < alphaTestSubMeshes.length; index++) {
this._renderSubMesh(alphaTestSubMeshes.data[index]);
}
const previousAlphaMode = engine.getAlphaMode();
for (index = 0; index < transparentSubMeshes.length; index++) {
const subMesh = transparentSubMeshes.data[index];
const material = subMesh.getMaterial();
if (material && material.needDepthPrePass) {
const engine = material.getScene().getEngine();
engine.setColorWrite(false);
this._renderSubMesh(subMesh);
engine.setColorWrite(true);
}
this._renderSubMesh(subMesh, true);
}
engine.setAlphaMode(previousAlphaMode);
};
}
/** @internal */
_addCustomEffectDefines(_defines) { }
/** @internal */
_internalIsSubMeshReady(subMesh, useInstances, emissiveTexture) {
const engine = this._scene.getEngine();
const mesh = subMesh.getMesh();
const renderingMaterial = mesh._internalAbstractMeshDataInfo._materialForRenderPass?.[engine.currentRenderPassId];
if (renderingMaterial) {
return renderingMaterial.isReadyForSubMesh(mesh, subMesh, useInstances);
}
const material = subMesh.getMaterial();
if (!material) {
return false;
}
if (this._useMeshMaterial(subMesh.getRenderingMesh())) {
return material.isReadyForSubMesh(subMesh.getMesh(), subMesh, useInstances);
}
const defines = [];
const attribs = [VertexBuffer.PositionKind];
let uv1 = false;
let uv2 = false;
const color = false;
// Diffuse
if (material) {
const needAlphaTest = material.needAlphaTestingForMesh(mesh);
const diffuseTexture = material.getAlphaTestTexture();
const needAlphaBlendFromDiffuse = diffuseTexture && diffuseTexture.hasAlpha && (material.useAlphaFromDiffuseTexture || material._useAlphaFromAlbedoTexture);
if (diffuseTexture && (needAlphaTest || needAlphaBlendFromDiffuse)) {
defines.push("#define DIFFUSE");
if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) && diffuseTexture.coordinatesIndex === 1) {
defines.push("#define DIFFUSEUV2");
uv2 = true;
}
else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
defines.push("#define DIFFUSEUV1");
uv1 = true;
}
if (needAlphaTest) {
defines.push("#define ALPHATEST");
defines.push("#define ALPHATESTVALUE 0.4");
}
if (!diffuseTexture.gammaSpace) {
defines.push("#define DIFFUSE_ISLINEAR");
}
}
const opacityTexture = material.opacityTexture;
if (opacityTexture) {
defines.push("#define OPACITY");
if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) && opacityTexture.coordinatesIndex === 1) {
defines.push("#define OPACITYUV2");
uv2 = true;
}
else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
defines.push("#define OPACITYUV1");
uv1 = true;
}
}
}
// Emissive
if (emissiveTexture) {
defines.push("#define EMISSIVE");
if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) && emissiveTexture.coordinatesIndex === 1) {
defines.push("#define EMISSIVEUV2");
uv2 = true;
}
else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
defines.push("#define EMISSIVEUV1");
uv1 = true;
}
if (!emissiveTexture.gammaSpace) {
defines.push("#define EMISSIVE_ISLINEAR");
}
}
// Vertex
if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind) && mesh.hasVertexAlpha && material.transparencyMode !== Material.MATERIAL_OPAQUE) {
attribs.push(VertexBuffer.ColorKind);
defines.push("#define VERTEXALPHA");
}
if (uv1) {
attribs.push(VertexBuffer.UVKind);
defines.push("#define UV1");
}
if (uv2) {
attribs.push(VertexBuffer.UV2Kind);
defines.push("#define UV2");
}
// Bones
const fallbacks = new EffectFallbacks();
if (mesh.useBones && mesh.computeBonesUsingShaders) {
attribs.push(VertexBuffer.MatricesIndicesKind);
attribs.push(VertexBuffer.MatricesWeightsKind);
if (mesh.numBoneInfluencers > 4) {
attribs.push(VertexBuffer.MatricesIndicesExtraKind);
attribs.push(VertexBuffer.MatricesWeightsExtraKind);
}
defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
const skeleton = mesh.skeleton;
if (skeleton && skeleton.isUsingTextureForMatrices) {
defines.push("#define BONETEXTURE");
}
else {
defines.push("#define BonesPerMesh " + (skeleton ? skeleton.bones.length + 1 : 0));
}
if (mesh.numBoneInfluencers > 0) {
fallbacks.addCPUSkinningFallback(0, mesh);
}
}
else {
defines.push("#define NUM_BONE_INFLUENCERS 0");
}
// Morph targets
const numMorphInfluencers = mesh.morphTargetManager
? PrepareDefinesAndAttributesForMorphTargets(mesh.morphTargetManager, defines, attribs, mesh, true, // usePositionMorph
false, // useNormalMorph
false, // useTangentMorph
uv1, // useUVMorph
uv2, // useUV2Morph
color // useColorMorph
)
: 0;
// Instances
if (useInstances) {
defines.push("#define INSTANCES");
PushAttributesForInstances(attribs);
if (subMesh.getRenderingMesh().hasThinInstances) {
defines.push("#define THIN_INSTANCES");
}
}
// ClipPlanes
PrepareStringDefinesForClipPlanes(material, this._scene, defines);
this._addCustomEffectDefines(defines);
// Get correct effect
const drawWrapper = subMesh._getDrawWrapper(undefined, true);
const cachedDefines = drawWrapper.defines;
const join = defines.join("\n");
if (cachedDefines !== join) {
const uniforms = [
"world",
"mBones",
"viewProjection",
"glowColor",
"morphTargetInfluences",
"morphTargetCount",
"boneTextureWidth",
"diffuseMatrix",
"emissiveMatrix",
"opacityMatrix",
"opacityIntensity",
"morphTargetTextureInfo",
"morphTargetTextureIndices",
"glowIntensity",
];
AddClipPlaneUniforms(uniforms);
drawWrapper.setEffect(this._engine.createEffect("glowMapGeneration", attribs, uniforms, ["diffuseSampler", "emissiveSampler", "opacitySampler", "boneSampler", "morphTargets"], join, fallbacks, undefined, undefined, { maxSimultaneousMorphTargets: numMorphInfluencers }, this._shaderLanguage, this._shadersLoaded
? undefined
: async () => {
await this._importShadersAsync();
this._shadersLoaded = true;
}), join);
}
const effectIsReady = drawWrapper.effect.isReady();
return effectIsReady && (this._dontCheckIfReady || (!this._dontCheckIfReady && this.isLayerReady()));
}
/** @internal */
_isSubMeshReady(subMesh, useInstances, emissiveTexture) {
return this._internalIsSubMeshReady(subMesh, useInstances, emissiveTexture);
}
async _importShadersAsync() {
if (this._shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
await Promise.all([import("../ShadersWGSL/glowMapGeneration.vertex.js"), import("../ShadersWGSL/glowMapGeneration.fragment.js")]);
}
else {
await Promise.all([import("../Shaders/glowMapGeneration.vertex.js"), import("../Shaders/glowMapGeneration.fragment.js")]);
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this._additionalImportShadersAsync?.();
}
/** @internal */
_internalIsLayerReady() {
let isReady = true;
for (let i = 0; i < this._postProcesses.length; i++) {
isReady = this._postProcesses[i].isReady() && isReady;
}
const numDraws = this._numInternalDraws();
for (let i = 0; i < numDraws; ++i) {
let currentEffect = this._mergeDrawWrapper[i];
if (!currentEffect) {
currentEffect = this._mergeDrawWrapper[i] = new DrawWrapper(this._engine);
currentEffect.setEffect(this._createMergeEffect());
}
isReady = currentEffect.effect.isReady() && isReady;
}
return isReady;
}
/**
* Checks if the layer is ready to be used.
* @returns true if the layer is ready to be used
*/
isLayerReady() {
return this._internalIsLayerReady();
}
/**
* Renders the glowing part of the scene by blending the blurred glowing meshes on top of the rendered scene.
* @returns true if the rendering was successful
*/
compose() {
if (!this._dontCheckIfReady && !this.isLayerReady()) {
return false;
}
const engine = this._scene.getEngine();
const numDraws = this._numInternalDraws();
this.onBeforeComposeObservable.notifyObservers(this);
const previousAlphaMode = engine.getAlphaMode();
for (let i = 0; i < numDraws; ++i) {
const currentEffect = this._mergeDrawWrapper[i];
// Render
engine.enableEffect(currentEffect);
engine.setState(false);
// VBOs
engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect.effect);
// Go Blend.
engine.setAlphaMode(this._options.alphaBlendingMode);
// Blends the map on the main canvas.
this._internalCompose(currentEffect.effect, i);
}
// Restore Alpha
engine.setAlphaMode(previousAlphaMode);
this.onAfterComposeObservable.notifyObservers(this);
return true;
}
/** @internal */
_internalHasMesh(mesh) {
if (this.renderingGroupId === -1 || mesh.renderingGroupId === this.renderingGroupId) {
return true;
}
return false;
}
/**
* Determine if a given mesh will be used in the current effect.
* @param mesh mesh to test
* @returns true if the mesh will be used
*/
hasMesh(mesh) {
return this._internalHasMesh(mesh);
}
/** @internal */
_internalShouldRender() {
return this.isEnabled && this._shouldRender;
}
/**
* Returns true if the layer contains information to display, otherwise false.
* @returns true if the glow layer should be rendered
*/
shouldRender() {
return this._internalShouldRender();
}
/** @internal */
_shouldRenderMesh(_mesh) {
return true;
}
/** @internal */
_internalCanRenderMesh(mesh, material) {
return !material.needAlphaBlendingForMesh(mesh);
}
/** @internal */
_canRenderMesh(mesh, material) {
return this._internalCanRenderMesh(mesh, material);
}
_renderSubMesh(subMesh, enableAlphaMode = false) {
if (!this._internalShouldRender()) {
return;
}
const material = subMesh.getMaterial();
const ownerMesh = subMesh.getMesh();
const replacementMesh = subMesh.getReplacementMesh();
const renderingMesh = subMesh.getRenderingMesh();
const effectiveMesh = subMesh.getEffectiveMesh();
const scene = this._scene;
const engine = scene.getEngine();
effectiveMesh._internalAbstractMeshDataInfo._isActiveIntermediate = false;
if (!material) {
return;
}
// Do not block in blend mode.
if (!this._canRenderMesh(renderingMesh, material)) {
return;
}
// Culling
let sideOrientation = material._getEffectiveOrientation(renderingMesh);
const mainDeterminant = effectiveMesh._getWorldMatrixDeterminant();
if (mainDeterminant < 0) {
sideOrientation = sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
}
const reverse = sideOrientation === Material.ClockWiseSideOrientation;
engine.setState(material.backFaceCulling, material.zOffset, undefined, reverse, material.cullBackFaces, undefined, material.zOffsetUnits);
// Managing instances
const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!replacementMesh);
if (batch.mustReturn) {
return;
}
// Early Exit per mesh
if (!this._shouldRenderMesh(renderingMesh)) {
return;
}
const hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id] || renderingMesh.hasThinInstances;
this._setEmissiveTextureAndColor(renderingMesh, subMesh, material);
this.onBeforeRenderMeshToEffect.notifyObservers(ownerMesh);
if (this._useMeshMaterial(renderingMesh)) {
subMesh.getMaterial()._glowModeEnabled = true;
renderingMesh.render(subMesh, enableAlphaMode, replacementMesh || undefined);
subMesh.getMaterial()._glowModeEnabled = false;
}
else if (this._isSubMeshReady(subMesh, hardwareInstancedRendering, this._emissiveTextureAndColor.texture)) {
const renderingMaterial = effectiveMesh._internalAbstractMeshDataInfo._materialForRenderPass?.[engine.currentRenderPassId];
let drawWrapper = subMesh._getDrawWrapper();
if (!drawWrapper && renderingMaterial) {
drawWrapper = renderingMaterial._getDrawWrapper();
}
if (!drawWrapper) {
return;
}
const effect = drawWrapper.effect;
engine.enableEffect(drawWrapper);
if (!hardwareInstancedRendering) {
renderingMesh._bind(subMesh, effect, material.fillMode);
}
if (!renderingMaterial) {
effect.setMatrix("viewProjection", scene.getTransformMatrix());
effect.setMatrix("world", effectiveMesh.getWorldMatrix());
effect.setFloat4("glowColor", this._emissiveTextureAndColor.color.r, this._emissiveTextureAndColor.color.g, this._emissiveTextureAndColor.color.b, this._emissiveTextureAndColor.color.a);
}
else {
renderingMaterial.bindForSubMesh(effectiveMesh.getWorldMatrix(), effectiveMesh, subMesh);
}
if (!renderingMaterial) {
const needAlphaTest = material.needAlphaTestingForMesh(effectiveMesh);
const diffuseTexture = material.getAlphaTestTexture();
const needAlphaBlendFromDiffuse = diffuseTexture && diffuseTexture.hasAlpha && (material.useAlphaFromDiffuseTexture || material._useAlphaFromAlbedoTexture);
if (diffuseTexture && (needAlphaTest || needAlphaBlendFromDiffuse)) {
effect.setTexture("diffuseSampler", diffuseTexture);
const textureMatrix = diffuseTexture.getTextureMatrix();
if (textureMatrix) {
effect.setMatrix("diffuseMatrix", textureMatrix);
}
}
const opacityTexture = material.opacityTexture;
if (opacityTexture) {
effect.setTexture("opacitySampler", opacityTexture);
effect.setFloat("opacityIntensity", opacityTexture.level);
const textureMatrix = opacityTexture.getTextureMatrix();
if (textureMatrix) {
effect.setMatrix("opacityMatrix", textureMatrix);
}
}
// Glow emissive only
if (this._emissiveTextureAndColor.texture) {
effect.setTexture("emissiveSampler", this._emissiveTextureAndColor.texture);
effect.setMatrix("emissiveMatrix", this._emissiveTextureAndColor.texture.getTextureMatrix());
}
// Bones
if (renderingMesh.useBones && renderingMesh.computeBonesUsingShaders && renderingMesh.skeleton) {
const skeleton = renderingMesh.skeleton;
if (skeleton.isUsingTextureForMatrices) {
const boneTexture = skeleton.getTransformMatrixTexture(renderingMesh);
if (!boneTexture) {
return;
}
effect.setTexture("boneSampler", boneTexture);
effect.setFloat("boneTextureWidth", 4.0 * (skeleton.bones.length + 1));
}
else {
effect.setMatrices("mBones", skeleton.getTransformMatrices(renderingMesh));
}
}
// Morph targets
BindMorphTargetParameters(renderingMesh, effect);
if (renderingMesh.morphTargetManager && renderingMesh.morphTargetManager.isUsingTextureForTargets) {
renderingMesh.morphTargetManager._bind(effect);
}
// Alpha mode
if (enableAlphaMode) {
engine.setAlphaMode(material.alphaMode);
}
// Intensity of effect
effect.setFloat("glowIntensity", this.getEffectIntensity(renderingMesh));
// Clip planes
BindClipPlane(effect, material, scene);
}
// Draw
renderingMesh._processRendering(effectiveMesh, subMesh, effect, material.fillMode, batch, hardwareInstancedRendering, (isInstance, world) => effect.setMatrix("world", world));
}
else {
// Need to reset refresh rate of the main map
this._objectRenderer.resetRefreshCounter();
}
this.onAfterRenderMeshToEffect.notifyObservers(ownerMesh);
}
/** @internal */
_useMeshMaterial(_mesh) {
return false;
}
/** @internal */
_rebuild() {
const vb = this._vertexBuffers[VertexBuffer.PositionKind];
if (vb) {
vb._rebuild();
}
this._generateIndexBuffer();
}
/**
* Dispose the effect layer and free resources.
*/
dispose() {
const vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
if (vertexBuffer) {
vertexBuffer.dispose();
this._vertexBuffers[VertexBuffer.PositionKind] = null;
}
if (this._indexBuffer) {
this._scene.getEngine()._releaseBuffer(this._indexBuffer);
this._indexBuffer = null;
}
for (const drawWrapper of this._mergeDrawWrapper) {
drawWrapper.dispose();
}
this._mergeDrawWrapper = [];
this._objectRenderer.dispose();
// Callback
this.onDisposeObservable.notifyObservers(this);
this.onDisposeObservable.clear();
this.onBeforeRenderLayerObservable.clear();
this.onBeforeComposeObservable.clear();
this.onBeforeRenderMeshToEffect.clear();
this.onAfterRenderMeshToEffect.clear();
this.onAfterComposeObservable.clear();
}
}
/**
* Force all the effect layers to compile to glsl even on WebGPU engines.
* False by default. This is mostly meant for backward compatibility.
*/
ThinEffectLayer.ForceGLSL = false;
//# sourceMappingURL=thinEffectLayer.js.map