UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

329 lines (328 loc) 13 kB
import { __decorate } from "../tslib.es6.js"; import { serialize, serializeAsColor3 } from "../Misc/decorators.js"; import { Scene } from "../scene.js"; import { EffectLayer } from "./effectLayer.js"; import { RegisterClass } from "../Misc/typeStore.js"; import { SerializationHelper } from "../Misc/decorators.serialization.js"; import { ThinSelectionOutlineLayer } from "./thinSelectionOutlineLayer.js"; import "../Rendering/depthRendererSceneComponent.js"; Scene.prototype.getSelectionOutlineLayerByName = function (name) { for (let index = 0; index < this.effectLayers?.length; index++) { if (this.effectLayers[index].name === name && this.effectLayers[index].getEffectName() === SelectionOutlineLayer.EffectName) { return this.effectLayers[index]; } } return null; }; /** * The selection outline layer Helps adding a outline effect around a mesh. * * Once instantiated in a scene, simply use the addMesh or removeMesh method to add or remove * outlined meshes to your scene. */ export class SelectionOutlineLayer extends EffectLayer { /** * Effect Name of the selection outline layer. */ static get EffectName() { return ThinSelectionOutlineLayer.EffectName; } /** * The outline color (default (1, 0.5, 0)) */ get outlineColor() { return this._thinEffectLayer.outlineColor; } set outlineColor(value) { this._thinEffectLayer.outlineColor = value; } /** * The thickness of the edges (default: 2.0) */ get outlineThickness() { return this._thinEffectLayer.outlineThickness; } set outlineThickness(value) { this._thinEffectLayer.outlineThickness = value; } /** * The strength of the occlusion effect (default: 0.8) */ get occlusionStrength() { return this._thinEffectLayer.occlusionStrength; } set occlusionStrength(value) { this._thinEffectLayer.occlusionStrength = value; } /** * The occlusion threshold (default: 0.01) */ get occlusionThreshold() { return this._thinEffectLayer.occlusionThreshold; } set occlusionThreshold(value) { this._thinEffectLayer.occlusionThreshold = value; } /** * Instantiates a new selection outline 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 ISelectionOutlineLayerOptions for more information) */ constructor(name, scene, options) { super(name, scene, options !== undefined ? !!options.forceGLSL : false, new ThinSelectionOutlineLayer(name, scene, options)); // Adapt options this._options = { mainTextureRatio: 1.0, mainTextureFixedSize: 0, alphaBlendingMode: 2, camera: null, mainTextureSamples: 1, renderingGroupId: -1, mainTextureType: 1, mainTextureFormat: 7, forceGLSL: false, storeCameraSpaceZ: false, outlineMethod: 0, ...options, }; // Fall back to a supported mask texture type if the device doesn't support rendering to float framebuffers // or linear filtering of float textures (e.g. OES_texture_float_linear missing on some iOS versions) if (this._options.mainTextureType === 1 && !(this._engine.getCaps().textureFloatRender && this._engine.getCaps().textureFloatLinearFiltering)) { this._options.mainTextureType = 2; } if (this._options.mainTextureType === 2 && !this._engine.getCaps().textureHalfFloatRender && !this._options.storeCameraSpaceZ) { this._options.mainTextureType = 0; } // Initialize the layer this._init(this._options); // Do not render as long as no meshes have been added this._shouldRender = false; this._scene.enableDepthRenderer(); } /** * Get the effect name of the layer. * @returns The effect name */ getEffectName() { return SelectionOutlineLayer.EffectName; } _numInternalDraws() { return 1; // draw depth mask on main pass and outline on merge pass } /** * 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. * @returns The effect created */ _createMergeEffect() { return this._thinEffectLayer._createMergeEffect(); } /** * Creates the render target textures and post processes used in the selection outline layer. */ _createTextureAndPostProcesses() { this._textures = []; this._thinEffectLayer.bindTexturesForCompose = (effect) => { effect.setTexture("maskSampler", this._mainTexture); const depthRenderer = this._scene.enableDepthRenderer(); effect.setTexture("depthSampler", depthRenderer.getDepthMap()); const mainTextureDesiredSize = this._mainTextureDesiredSize; this._thinEffectLayer.textureWidth = mainTextureDesiredSize.width; this._thinEffectLayer.textureHeight = mainTextureDesiredSize.height; }; this._thinEffectLayer._createTextureAndPostProcesses(); this._postProcesses = []; this._mainTexture.samples = this._options.mainTextureSamples; this._mainTexture.onAfterUnbindObservable.add(() => { // glow layer and highlight layer both call this._scene.postProcessManager.directRender // when you call this._scene.postProcessManager.directRender, it has 4 side effects: // 1. binds the framebuffer // 2. setAlphaMode(ALPHA_DISABLE) // 3. setDepthBuffer(true) // 4. setDepthWrite(true) // glow layer and highlight layer are restore framebuffer and depends on other side effects // but for now 3 and 4 are not needed to resolve the state management issue, so we just restore alpha mode this._scene.getEngine().setAlphaMode(0); }); } /** * Creates the main texture for the effect layer. */ _createMainTexture() { super._createMainTexture(); // set the render list for selective rendering this._mainTexture.renderList = this._thinEffectLayer._selection; } /** * @returns whether or not the layer needs stencil enabled during the mesh rendering. */ needStencil() { return this._thinEffectLayer.needStencil(); } /** * 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); } /** * Implementation specific of rendering the generating effect on the main canvas. * @param effect The effect used to render through * @param renderIndex */ _internalRender(effect, renderIndex) { this._thinEffectLayer._internalCompose(effect, renderIndex); } /** * @returns true if the layer contains information to display, otherwise false. */ shouldRender() { return this._thinEffectLayer.shouldRender(); } /** * 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); } /** * 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); } /** * Adds specific effects defines. * @param defines The defines to add specifics to. */ _addCustomEffectDefines(defines) { this._thinEffectLayer._addCustomEffectDefines(defines); } /** * 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); } /** * Determine if a given mesh will be highlighted by the current SelectionOutlineLayer * @param mesh mesh to test * @returns true if the mesh will be highlighted by the current SelectionOutlineLayer */ hasMesh(mesh) { return this._thinEffectLayer.hasMesh(mesh); } /** * Remove all the meshes currently referenced in the selection outline layer */ clearSelection() { this._thinEffectLayer.clearSelection(); this._mainTexture.renderList = this._thinEffectLayer._selection; // update render list } /** * Adds mesh or group of mesh to the current selection * * If a group of meshes is provided, they will outline as a single unit * @param meshOrGroup Meshes to add to the selection */ addSelection(meshOrGroup) { this._thinEffectLayer.addSelection(meshOrGroup); } /** * 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 "SelectionOutlineLayer"; } /** * Serializes this SelectionOutline layer * @returns a serialized SelectionOutline layer object */ serialize() { const serializationObject = SerializationHelper.Serialize(this); serializationObject.customType = "BABYLON.SelectionOutlineLayer"; // Selected meshes serializationObject.selection = []; const selection = this._thinEffectLayer._selection; if (selection) { const meshUniqueIdToSelectionId = this._thinEffectLayer._meshUniqueIdToSelectionId; // selection can be sparse since _removeMesh can remove entries const selectionMap = {}; for (let i = 0; i < selection.length; ++i) { const mesh = selection[i]; const selectionId = meshUniqueIdToSelectionId[mesh.uniqueId]; if (!selectionMap[selectionId]) { selectionMap[selectionId] = { meshIds: [], }; } selectionMap[selectionId].meshIds.push(mesh.id); } serializationObject.selection = selectionMap; } return serializationObject; } /** * Creates a SelectionOutline layer from parsed SelectionOutline layer data * @param parsedSelectionOutlineLayer defines the SelectionOutline layer data * @param scene defines the current scene * @param rootUrl defines the root URL containing the SelectionOutline layer information * @returns a parsed SelectionOutline layer */ static Parse(parsedSelectionOutlineLayer, scene, rootUrl) { const selectionOutlineLayer = SerializationHelper.Parse(() => new SelectionOutlineLayer(parsedSelectionOutlineLayer.name, scene, parsedSelectionOutlineLayer.options), parsedSelectionOutlineLayer, scene, rootUrl); const selectionMap = parsedSelectionOutlineLayer.selection; // Selected meshes for (const outlinedMeshes of Object.values(selectionMap)) { const meshes = []; for (let meshIndex = 0; meshIndex < outlinedMeshes.meshIds.length; meshIndex++) { const meshId = outlinedMeshes.meshIds[meshIndex]; const mesh = scene.getMeshById(meshId); if (mesh) { meshes.push(mesh); } } selectionOutlineLayer.addSelection(meshes); } return selectionOutlineLayer; } } __decorate([ serializeAsColor3() ], SelectionOutlineLayer.prototype, "outlineColor", null); __decorate([ serialize() ], SelectionOutlineLayer.prototype, "outlineThickness", null); __decorate([ serialize() ], SelectionOutlineLayer.prototype, "occlusionStrength", null); __decorate([ serialize() ], SelectionOutlineLayer.prototype, "occlusionThreshold", null); __decorate([ serialize("options") ], SelectionOutlineLayer.prototype, "_options", void 0); RegisterClass("BABYLON.SelectionOutlineLayer", SelectionOutlineLayer); //# sourceMappingURL=selectionOutlineLayer.js.map