@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.
436 lines (435 loc) • 17.9 kB
JavaScript
import { __decorate } from "../tslib.es6.js";
/* eslint-disable @typescript-eslint/no-unused-vars */
import { serialize } from "../Misc/decorators.js";
import { Scene } from "../scene.js";
import { Texture } from "../Materials/Textures/texture.js";
import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture.js";
import { BlurPostProcess } from "../PostProcesses/blurPostProcess.js";
import { EffectLayer } from "./effectLayer.js";
import { RegisterClass } from "../Misc/typeStore.js";
import "../Layers/effectLayerSceneComponent.js";
import { SerializationHelper } from "../Misc/decorators.serialization.js";
import { GetExponentOfTwo } from "../Misc/tools.functions.js";
import { ThinGlowLayer } from "./thinGlowLayer.js";
Scene.prototype.getGlowLayerByName = function (name) {
for (let index = 0; index < this.effectLayers?.length; index++) {
if (this.effectLayers[index].name === name && this.effectLayers[index].getEffectName() === GlowLayer.EffectName) {
return this.effectLayers[index];
}
}
return null;
};
/**
* The glow layer Helps adding a glow effect around the emissive parts of a mesh.
*
* Once instantiated in a scene, by default, all the emissive meshes will glow.
*
* Documentation: https://doc.babylonjs.com/features/featuresDeepDive/mesh/glowLayer
*/
export class GlowLayer extends EffectLayer {
/**
* Effect Name of the layer.
*/
static get EffectName() {
return ThinGlowLayer.EffectName;
}
/**
* Sets the kernel size of the blur.
*/
set blurKernelSize(value) {
this._thinEffectLayer.blurKernelSize = value;
}
/**
* Gets the kernel size of the blur.
*/
get blurKernelSize() {
return this._thinEffectLayer.blurKernelSize;
}
/**
* Sets the glow intensity.
*/
set intensity(value) {
this._thinEffectLayer.intensity = value;
}
/**
* Gets the glow intensity.
*/
get intensity() {
return this._thinEffectLayer.intensity;
}
/**
* Callback used to let the user override the color selection on a per mesh basis
*/
get customEmissiveColorSelector() {
return this._thinEffectLayer.customEmissiveColorSelector;
}
set customEmissiveColorSelector(value) {
this._thinEffectLayer.customEmissiveColorSelector = value;
}
/**
* Callback used to let the user override the texture selection on a per mesh basis
*/
get customEmissiveTextureSelector() {
return this._thinEffectLayer.customEmissiveTextureSelector;
}
set customEmissiveTextureSelector(value) {
this._thinEffectLayer.customEmissiveTextureSelector = value;
}
/**
* Instantiates a new glow Layer and references it to the scene.
* @param name The name of the layer
* @param scene The scene to use the layer in
* @param options Sets of none mandatory options to use with the layer (see IGlowLayerOptions for more information)
*/
constructor(name, scene, options) {
super(name, scene, false, new ThinGlowLayer(name, scene, options));
// Adapt options
this._options = {
mainTextureRatio: GlowLayer.DefaultTextureRatio,
blurKernelSize: 32,
mainTextureFixedSize: undefined,
camera: null,
mainTextureSamples: 1,
renderingGroupId: -1,
ldrMerge: false,
alphaBlendingMode: 1,
mainTextureType: 0,
generateStencilBuffer: false,
...options,
};
// Initialize the layer
this._init(this._options);
}
/**
* Get the effect name of the layer.
* @returns The effect name
*/
getEffectName() {
return GlowLayer.EffectName;
}
/**
* @internal
* Create the merge effect. This is the shader use to blit the information back
* to the main canvas at the end of the scene rendering.
*/
_createMergeEffect() {
return this._thinEffectLayer._createMergeEffect();
}
/**
* Creates the render target textures and post processes used in the glow layer.
*/
_createTextureAndPostProcesses() {
this._thinEffectLayer._renderPassId = this._mainTexture.renderPassId;
let blurTextureWidth = this._mainTextureDesiredSize.width;
let blurTextureHeight = this._mainTextureDesiredSize.height;
blurTextureWidth = this._engine.needPOTTextures ? GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
blurTextureHeight = this._engine.needPOTTextures ? GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
let textureType = 0;
if (this._engine.getCaps().textureHalfFloatRender) {
textureType = 2;
}
else {
textureType = 0;
}
this._blurTexture1 = new RenderTargetTexture("GlowLayerBlurRTT", {
width: blurTextureWidth,
height: blurTextureHeight,
}, this._scene, false, true, textureType);
this._blurTexture1.wrapU = Texture.CLAMP_ADDRESSMODE;
this._blurTexture1.wrapV = Texture.CLAMP_ADDRESSMODE;
this._blurTexture1.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
this._blurTexture1.renderParticles = false;
this._blurTexture1.ignoreCameraViewport = true;
const blurTextureWidth2 = Math.floor(blurTextureWidth / 2);
const blurTextureHeight2 = Math.floor(blurTextureHeight / 2);
this._blurTexture2 = new RenderTargetTexture("GlowLayerBlurRTT2", {
width: blurTextureWidth2,
height: blurTextureHeight2,
}, this._scene, false, true, textureType);
this._blurTexture2.wrapU = Texture.CLAMP_ADDRESSMODE;
this._blurTexture2.wrapV = Texture.CLAMP_ADDRESSMODE;
this._blurTexture2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
this._blurTexture2.renderParticles = false;
this._blurTexture2.ignoreCameraViewport = true;
this._textures = [this._blurTexture1, this._blurTexture2];
this._thinEffectLayer.bindTexturesForCompose = (effect) => {
effect.setTexture("textureSampler", this._blurTexture1);
effect.setTexture("textureSampler2", this._blurTexture2);
effect.setFloat("offset", this.intensity);
};
this._thinEffectLayer._createTextureAndPostProcesses();
const thinBlurPostProcesses1 = this._thinEffectLayer._postProcesses[0];
this._horizontalBlurPostprocess1 = new BlurPostProcess("GlowLayerHBP1", thinBlurPostProcesses1.direction, thinBlurPostProcesses1.kernel, {
samplingMode: Texture.BILINEAR_SAMPLINGMODE,
engine: this._scene.getEngine(),
width: blurTextureWidth,
height: blurTextureHeight,
textureType,
effectWrapper: thinBlurPostProcesses1,
});
this._horizontalBlurPostprocess1.width = blurTextureWidth;
this._horizontalBlurPostprocess1.height = blurTextureHeight;
this._horizontalBlurPostprocess1.externalTextureSamplerBinding = true;
this._horizontalBlurPostprocess1.onApplyObservable.add((effect) => {
effect.setTexture("textureSampler", this._mainTexture);
});
const thinBlurPostProcesses2 = this._thinEffectLayer._postProcesses[1];
this._verticalBlurPostprocess1 = new BlurPostProcess("GlowLayerVBP1", thinBlurPostProcesses2.direction, thinBlurPostProcesses2.kernel, {
samplingMode: Texture.BILINEAR_SAMPLINGMODE,
engine: this._scene.getEngine(),
width: blurTextureWidth,
height: blurTextureHeight,
textureType,
effectWrapper: thinBlurPostProcesses2,
});
const thinBlurPostProcesses3 = this._thinEffectLayer._postProcesses[2];
this._horizontalBlurPostprocess2 = new BlurPostProcess("GlowLayerHBP2", thinBlurPostProcesses3.direction, thinBlurPostProcesses3.kernel, {
samplingMode: Texture.BILINEAR_SAMPLINGMODE,
engine: this._scene.getEngine(),
width: blurTextureWidth2,
height: blurTextureHeight2,
textureType,
effectWrapper: thinBlurPostProcesses3,
});
this._horizontalBlurPostprocess2.width = blurTextureWidth2;
this._horizontalBlurPostprocess2.height = blurTextureHeight2;
this._horizontalBlurPostprocess2.externalTextureSamplerBinding = true;
this._horizontalBlurPostprocess2.onApplyObservable.add((effect) => {
effect.setTexture("textureSampler", this._blurTexture1);
});
const thinBlurPostProcesses4 = this._thinEffectLayer._postProcesses[3];
this._verticalBlurPostprocess2 = new BlurPostProcess("GlowLayerVBP2", thinBlurPostProcesses4.direction, thinBlurPostProcesses4.kernel, {
samplingMode: Texture.BILINEAR_SAMPLINGMODE,
engine: this._scene.getEngine(),
width: blurTextureWidth2,
height: blurTextureHeight2,
textureType,
effectWrapper: thinBlurPostProcesses4,
});
this._postProcesses = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1, this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2];
this._postProcesses1 = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1];
this._postProcesses2 = [this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2];
this._mainTexture.samples = this._options.mainTextureSamples;
this._mainTexture.onAfterUnbindObservable.add(() => {
const internalTexture = this._blurTexture1.renderTarget;
if (internalTexture) {
this._scene.postProcessManager.directRender(this._postProcesses1, internalTexture, true);
const internalTexture2 = this._blurTexture2.renderTarget;
if (internalTexture2) {
this._scene.postProcessManager.directRender(this._postProcesses2, internalTexture2, true);
}
this._engine.unBindFramebuffer(internalTexture2 ?? internalTexture, true);
}
});
// Prevent autoClear.
this._postProcesses.map((pp) => {
pp.autoClear = false;
});
}
/**
* 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 this._thinEffectLayer.isReady(subMesh, useInstances);
}
/**
* @returns whether or not the layer needs stencil enabled during the mesh rendering.
*/
needStencil() {
return false;
}
/**
* Returns true if the mesh can be rendered, otherwise false.
* @param mesh The mesh to render
* @param material The material used on the mesh
* @returns true if it can be rendered otherwise false
*/
_canRenderMesh(mesh, material) {
return this._thinEffectLayer._canRenderMesh(mesh, material);
}
/**
* Implementation specific of rendering the generating effect on the main canvas.
* @param effect The effect used to render through
*/
_internalRender(effect) {
this._thinEffectLayer._internalCompose(effect);
}
/**
* Sets the required values for both the emissive texture and and the main color.
* @param mesh
* @param subMesh
* @param material
*/
_setEmissiveTextureAndColor(mesh, subMesh, material) {
this._thinEffectLayer._setEmissiveTextureAndColor(mesh, subMesh, material);
}
/**
* Returns true if the mesh should render, otherwise false.
* @param mesh The mesh to render
* @returns true if it should render otherwise false
*/
_shouldRenderMesh(mesh) {
return this._thinEffectLayer._shouldRenderMesh(mesh);
}
/**
* Adds specific effects defines.
* @param defines The defines to add specifics to.
*/
_addCustomEffectDefines(defines) {
this._thinEffectLayer._addCustomEffectDefines(defines);
}
/**
* Add a mesh in the exclusion list to prevent it to impact or being impacted by the glow layer.
* @param mesh The mesh to exclude from the glow layer
*/
addExcludedMesh(mesh) {
this._thinEffectLayer.addExcludedMesh(mesh);
}
/**
* Remove a mesh from the exclusion list to let it impact or being impacted by the glow layer.
* @param mesh The mesh to remove
*/
removeExcludedMesh(mesh) {
this._thinEffectLayer.removeExcludedMesh(mesh);
}
/**
* Add a mesh in the inclusion list to impact or being impacted by the glow layer.
* @param mesh The mesh to include in the glow layer
*/
addIncludedOnlyMesh(mesh) {
this._thinEffectLayer.addIncludedOnlyMesh(mesh);
}
/**
* Remove a mesh from the Inclusion list to prevent it to impact or being impacted by the glow layer.
* @param mesh The mesh to remove
*/
removeIncludedOnlyMesh(mesh) {
this._thinEffectLayer.removeIncludedOnlyMesh(mesh);
}
/**
* Determine if a given mesh will be used in the glow layer
* @param mesh The mesh to test
* @returns true if the mesh will be highlighted by the current glow layer
*/
hasMesh(mesh) {
return this._thinEffectLayer.hasMesh(mesh);
}
/**
* Defines whether the current material of the mesh should be use to render the effect.
* @param mesh defines the current mesh to render
* @returns true if the material of the mesh should be use to render the effect
*/
_useMeshMaterial(mesh) {
return this._thinEffectLayer._useMeshMaterial(mesh);
}
/**
* Add a mesh to be rendered through its own material and not with emissive only.
* @param mesh The mesh for which we need to use its material
*/
referenceMeshToUseItsOwnMaterial(mesh) {
this._thinEffectLayer.referenceMeshToUseItsOwnMaterial(mesh);
}
/**
* Remove a mesh from being rendered through its own material and not with emissive only.
* @param mesh The mesh for which we need to not use its material
*/
unReferenceMeshFromUsingItsOwnMaterial(mesh) {
this._thinEffectLayer.unReferenceMeshFromUsingItsOwnMaterial(mesh, this._mainTexture.renderPassId);
}
/**
* Free any resources and references associated to a mesh.
* Internal use
* @param mesh The mesh to free.
* @internal
*/
_disposeMesh(mesh) {
this._thinEffectLayer._disposeMesh(mesh);
}
/**
* Gets the class name of the effect layer
* @returns the string with the class name of the effect layer
*/
getClassName() {
return "GlowLayer";
}
/**
* Serializes this glow layer
* @returns a serialized glow layer object
*/
serialize() {
const serializationObject = SerializationHelper.Serialize(this);
serializationObject.customType = "BABYLON.GlowLayer";
let index;
// Included meshes
serializationObject.includedMeshes = [];
const includedOnlyMeshes = this._thinEffectLayer._includedOnlyMeshes;
if (includedOnlyMeshes.length) {
for (index = 0; index < includedOnlyMeshes.length; index++) {
const mesh = this._scene.getMeshByUniqueId(includedOnlyMeshes[index]);
if (mesh) {
serializationObject.includedMeshes.push(mesh.id);
}
}
}
// Excluded meshes
serializationObject.excludedMeshes = [];
const excludedMeshes = this._thinEffectLayer._excludedMeshes;
if (excludedMeshes.length) {
for (index = 0; index < excludedMeshes.length; index++) {
const mesh = this._scene.getMeshByUniqueId(excludedMeshes[index]);
if (mesh) {
serializationObject.excludedMeshes.push(mesh.id);
}
}
}
return serializationObject;
}
/**
* Creates a Glow Layer from parsed glow layer data
* @param parsedGlowLayer defines glow layer data
* @param scene defines the current scene
* @param rootUrl defines the root URL containing the glow layer information
* @returns a parsed Glow Layer
*/
static Parse(parsedGlowLayer, scene, rootUrl) {
const gl = SerializationHelper.Parse(() => new GlowLayer(parsedGlowLayer.name, scene, parsedGlowLayer.options), parsedGlowLayer, scene, rootUrl);
let index;
// Excluded meshes
for (index = 0; index < parsedGlowLayer.excludedMeshes.length; index++) {
const mesh = scene.getMeshById(parsedGlowLayer.excludedMeshes[index]);
if (mesh) {
gl.addExcludedMesh(mesh);
}
}
// Included meshes
for (index = 0; index < parsedGlowLayer.includedMeshes.length; index++) {
const mesh = scene.getMeshById(parsedGlowLayer.includedMeshes[index]);
if (mesh) {
gl.addIncludedOnlyMesh(mesh);
}
}
return gl;
}
}
/**
* The default blur kernel size used for the glow.
*/
GlowLayer.DefaultBlurKernelSize = 32;
/**
* The default texture size ratio used for the glow.
*/
GlowLayer.DefaultTextureRatio = 0.5;
__decorate([
serialize()
], GlowLayer.prototype, "blurKernelSize", null);
__decorate([
serialize()
], GlowLayer.prototype, "intensity", null);
__decorate([
serialize("options")
], GlowLayer.prototype, "_options", void 0);
RegisterClass("BABYLON.GlowLayer", GlowLayer);
//# sourceMappingURL=glowLayer.js.map