123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- import { __decorate } from "../tslib.es6.js";
- /* eslint-disable @typescript-eslint/no-unused-vars */
- import { serialize } from "../Misc/decorators.js";
- import { Vector2 } from "../Maths/math.vector.js";
- import { VertexBuffer } from "../Buffers/buffer.js";
- import { Texture } from "../Materials/Textures/texture.js";
- import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture.js";
- import { Material } from "../Materials/material.js";
- import { BlurPostProcess } from "../PostProcesses/blurPostProcess.js";
- import { EffectLayer } from "./effectLayer.js";
- import { AbstractScene } from "../abstractScene.js";
- import { RegisterClass } from "../Misc/typeStore.js";
- import { Color4 } from "../Maths/math.color.js";
- import "../Shaders/glowMapMerge.fragment.js";
- import "../Shaders/glowMapMerge.vertex.js";
- import "../Layers/effectLayerSceneComponent.js";
- import { SerializationHelper } from "../Misc/decorators.serialization.js";
- import { GetExponentOfTwo } from "../Misc/tools.functions.js";
- AbstractScene.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 {
- /**
- * Sets the kernel size of the blur.
- */
- set blurKernelSize(value) {
- if (value === this._options.blurKernelSize) {
- return;
- }
- this._options.blurKernelSize = value;
- const effectiveKernel = this._getEffectiveBlurKernelSize();
- this._horizontalBlurPostprocess1.kernel = effectiveKernel;
- this._verticalBlurPostprocess1.kernel = effectiveKernel;
- this._horizontalBlurPostprocess2.kernel = effectiveKernel;
- this._verticalBlurPostprocess2.kernel = effectiveKernel;
- }
- /**
- * Gets the kernel size of the blur.
- */
- get blurKernelSize() {
- return this._options.blurKernelSize;
- }
- /**
- * Sets the glow intensity.
- */
- set intensity(value) {
- this._intensity = value;
- }
- /**
- * Gets the glow intensity.
- */
- get intensity() {
- return this._intensity;
- }
- /**
- * 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);
- this._intensity = 1.0;
- this._includedOnlyMeshes = [];
- this._excludedMeshes = [];
- this._meshesUsingTheirOwnMaterials = [];
- this.neutralColor = new Color4(0, 0, 0, 1);
- // 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({
- alphaBlendingMode: this._options.alphaBlendingMode,
- camera: this._options.camera,
- mainTextureFixedSize: this._options.mainTextureFixedSize,
- mainTextureRatio: this._options.mainTextureRatio,
- renderingGroupId: this._options.renderingGroupId,
- mainTextureType: this._options.mainTextureType,
- generateStencilBuffer: this._options.generateStencilBuffer,
- });
- }
- /**
- * 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() {
- let defines = "#define EMISSIVE \n";
- if (this._options.ldrMerge) {
- defines += "#define LDR \n";
- }
- // Effect
- return this._engine.createEffect("glowMapMerge", [VertexBuffer.PositionKind], ["offset"], ["textureSampler", "textureSampler2"], defines);
- }
- /**
- * Creates the render target textures and post processes used in the glow layer.
- */
- _createTextureAndPostProcesses() {
- 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];
- const effectiveKernel = this._getEffectiveBlurKernelSize();
- this._horizontalBlurPostprocess1 = new BlurPostProcess("GlowLayerHBP1", new Vector2(1.0, 0), effectiveKernel, {
- width: blurTextureWidth,
- height: blurTextureHeight,
- }, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
- this._horizontalBlurPostprocess1.width = blurTextureWidth;
- this._horizontalBlurPostprocess1.height = blurTextureHeight;
- this._horizontalBlurPostprocess1.externalTextureSamplerBinding = true;
- this._horizontalBlurPostprocess1.onApplyObservable.add((effect) => {
- effect.setTexture("textureSampler", this._mainTexture);
- });
- this._verticalBlurPostprocess1 = new BlurPostProcess("GlowLayerVBP1", new Vector2(0, 1.0), effectiveKernel, {
- width: blurTextureWidth,
- height: blurTextureHeight,
- }, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
- this._horizontalBlurPostprocess2 = new BlurPostProcess("GlowLayerHBP2", new Vector2(1.0, 0), effectiveKernel, {
- width: blurTextureWidth2,
- height: blurTextureHeight2,
- }, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
- this._horizontalBlurPostprocess2.width = blurTextureWidth2;
- this._horizontalBlurPostprocess2.height = blurTextureHeight2;
- this._horizontalBlurPostprocess2.externalTextureSamplerBinding = true;
- this._horizontalBlurPostprocess2.onApplyObservable.add((effect) => {
- effect.setTexture("textureSampler", this._blurTexture1);
- });
- this._verticalBlurPostprocess2 = new BlurPostProcess("GlowLayerVBP2", new Vector2(0, 1.0), effectiveKernel, {
- width: blurTextureWidth2,
- height: blurTextureHeight2,
- }, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
- 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;
- });
- }
- /**
- * @returns The blur kernel size used by the glow.
- * Note: The value passed in the options is divided by 2 for back compatibility.
- */
- _getEffectiveBlurKernelSize() {
- return this._options.blurKernelSize / 2;
- }
- /**
- * 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) {
- const material = subMesh.getMaterial();
- const mesh = subMesh.getRenderingMesh();
- if (!material || !mesh) {
- return false;
- }
- const emissiveTexture = material.emissiveTexture;
- return super._isReady(subMesh, useInstances, emissiveTexture);
- }
- /**
- * @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 true;
- }
- /**
- * Implementation specific of rendering the generating effect on the main canvas.
- * @param effect The effect used to render through
- */
- _internalRender(effect) {
- // Texture
- effect.setTexture("textureSampler", this._blurTexture1);
- effect.setTexture("textureSampler2", this._blurTexture2);
- effect.setFloat("offset", this._intensity);
- // Cache
- const engine = this._engine;
- const previousStencilBuffer = engine.getStencilBuffer();
- // Draw order
- engine.setStencilBuffer(false);
- engine.drawElementsType(Material.TriangleFillMode, 0, 6);
- // Draw order
- engine.setStencilBuffer(previousStencilBuffer);
- }
- /**
- * Sets the required values for both the emissive texture and and the main color.
- * @param mesh
- * @param subMesh
- * @param material
- */
- _setEmissiveTextureAndColor(mesh, subMesh, material) {
- let textureLevel = 1.0;
- if (this.customEmissiveTextureSelector) {
- this._emissiveTextureAndColor.texture = this.customEmissiveTextureSelector(mesh, subMesh, material);
- }
- else {
- if (material) {
- this._emissiveTextureAndColor.texture = material.emissiveTexture;
- if (this._emissiveTextureAndColor.texture) {
- textureLevel = this._emissiveTextureAndColor.texture.level;
- }
- }
- else {
- this._emissiveTextureAndColor.texture = null;
- }
- }
- if (this.customEmissiveColorSelector) {
- this.customEmissiveColorSelector(mesh, subMesh, material, this._emissiveTextureAndColor.color);
- }
- else {
- if (material.emissiveColor) {
- const emissiveIntensity = material.emissiveIntensity ?? 1;
- textureLevel *= emissiveIntensity;
- this._emissiveTextureAndColor.color.set(material.emissiveColor.r * textureLevel, material.emissiveColor.g * textureLevel, material.emissiveColor.b * textureLevel, material.alpha);
- }
- else {
- this._emissiveTextureAndColor.color.set(this.neutralColor.r, this.neutralColor.g, this.neutralColor.b, this.neutralColor.a);
- }
- }
- }
- /**
- * 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.hasMesh(mesh);
- }
- /**
- * Adds specific effects defines.
- * @param defines The defines to add specifics to.
- */
- _addCustomEffectDefines(defines) {
- defines.push("#define GLOW");
- }
- /**
- * 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) {
- if (this._excludedMeshes.indexOf(mesh.uniqueId) === -1) {
- this._excludedMeshes.push(mesh.uniqueId);
- }
- }
- /**
- * 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) {
- const index = this._excludedMeshes.indexOf(mesh.uniqueId);
- if (index !== -1) {
- this._excludedMeshes.splice(index, 1);
- }
- }
- /**
- * 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) {
- if (this._includedOnlyMeshes.indexOf(mesh.uniqueId) === -1) {
- this._includedOnlyMeshes.push(mesh.uniqueId);
- }
- }
- /**
- * 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) {
- const index = this._includedOnlyMeshes.indexOf(mesh.uniqueId);
- if (index !== -1) {
- this._includedOnlyMeshes.splice(index, 1);
- }
- }
- /**
- * 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) {
- if (!super.hasMesh(mesh)) {
- return false;
- }
- // Included Mesh
- if (this._includedOnlyMeshes.length) {
- return this._includedOnlyMeshes.indexOf(mesh.uniqueId) !== -1;
- }
- // Excluded Mesh
- if (this._excludedMeshes.length) {
- return this._excludedMeshes.indexOf(mesh.uniqueId) === -1;
- }
- return true;
- }
- /**
- * 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) {
- if (this._meshesUsingTheirOwnMaterials.length == 0) {
- return false;
- }
- return this._meshesUsingTheirOwnMaterials.indexOf(mesh.uniqueId) > -1;
- }
- /**
- * 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) {
- mesh.resetDrawCache(this._mainTexture.renderPassId);
- this._meshesUsingTheirOwnMaterials.push(mesh.uniqueId);
- mesh.onDisposeObservable.add(() => {
- this._disposeMesh(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) {
- let index = this._meshesUsingTheirOwnMaterials.indexOf(mesh.uniqueId);
- while (index >= 0) {
- this._meshesUsingTheirOwnMaterials.splice(index, 1);
- index = this._meshesUsingTheirOwnMaterials.indexOf(mesh.uniqueId);
- }
- mesh.resetDrawCache(this._mainTexture.renderPassId);
- }
- /**
- * Free any resources and references associated to a mesh.
- * Internal use
- * @param mesh The mesh to free.
- * @internal
- */
- _disposeMesh(mesh) {
- this.removeIncludedOnlyMesh(mesh);
- this.removeExcludedMesh(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 = [];
- if (this._includedOnlyMeshes.length) {
- for (index = 0; index < this._includedOnlyMeshes.length; index++) {
- const mesh = this._scene.getMeshByUniqueId(this._includedOnlyMeshes[index]);
- if (mesh) {
- serializationObject.includedMeshes.push(mesh.id);
- }
- }
- }
- // Excluded meshes
- serializationObject.excludedMeshes = [];
- if (this._excludedMeshes.length) {
- for (index = 0; index < this._excludedMeshes.length; index++) {
- const mesh = this._scene.getMeshByUniqueId(this._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;
- }
- }
- /**
- * Effect Name of the layer.
- */
- GlowLayer.EffectName = "GlowLayer";
- /**
- * 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
|