UNPKG

@itwin/core-frontend

Version:
281 lines • 16.5 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.EyeDomeLighting = exports.EDLMode = void 0; /** @packageDocumentation * @module WebGL */ const core_bentley_1 = require("@itwin/core-bentley"); const CachedGeometry_1 = require("./CachedGeometry"); const FrameBuffer_1 = require("./FrameBuffer"); const GL_1 = require("./GL"); const RenderState_1 = require("./RenderState"); const SceneCompositor_1 = require("./SceneCompositor"); const ScratchDrawParams_1 = require("./ScratchDrawParams"); const System_1 = require("./System"); const Texture_1 = require("./Texture"); class Bundle { edlCalcTex1; edlCalcTex2; edlCalcTex4; edlFiltTex2; edlFiltTex4; edlCalcFbo1; edlCalcFbo2; edlCalcFbo4; edlFiltFbo2; edlFiltFbo4; edlCalcBasicGeom; edlCalcFullGeom; edlFiltGeom; edlMixGeom; constructor(edlCalcTex1, edlCalcTex2, edlCalcTex4, edlFiltTex2, edlFiltTex4, edlCalcFbo1, edlCalcFbo2, edlCalcFbo4, edlFiltFbo2, edlFiltFbo4, edlCalcBasicGeom, edlCalcFullGeom, edlFiltGeom, edlMixGeom) { this.edlCalcTex1 = edlCalcTex1; this.edlCalcTex2 = edlCalcTex2; this.edlCalcTex4 = edlCalcTex4; this.edlFiltTex2 = edlFiltTex2; this.edlFiltTex4 = edlFiltTex4; this.edlCalcFbo1 = edlCalcFbo1; this.edlCalcFbo2 = edlCalcFbo2; this.edlCalcFbo4 = edlCalcFbo4; this.edlFiltFbo2 = edlFiltFbo2; this.edlFiltFbo4 = edlFiltFbo4; this.edlCalcBasicGeom = edlCalcBasicGeom; this.edlCalcFullGeom = edlCalcFullGeom; this.edlFiltGeom = edlFiltGeom; this.edlMixGeom = edlMixGeom; } static create(width, height) { const edlCalcTex1 = Texture_1.TextureHandle.createForAttachment(width, height, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte); const edlCalcTex2 = Texture_1.TextureHandle.createForAttachment(width >> 1, height >> 1, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte); const edlCalcTex4 = Texture_1.TextureHandle.createForAttachment(width >> 2, height >> 2, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte); const edlFiltTex2 = Texture_1.TextureHandle.createForAttachment(width >> 1, height >> 1, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte); const edlFiltTex4 = Texture_1.TextureHandle.createForAttachment(width >> 2, height >> 2, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte); if (undefined === edlCalcTex1 || undefined === edlCalcTex2 || undefined === edlCalcTex4 || undefined === edlFiltTex2 || undefined === edlFiltTex4) { (0, core_bentley_1.dispose)(edlCalcTex1); (0, core_bentley_1.dispose)(edlCalcTex2); (0, core_bentley_1.dispose)(edlCalcTex4); (0, core_bentley_1.dispose)(edlFiltTex2); (0, core_bentley_1.dispose)(edlFiltTex4); return undefined; } const edlCalcFbo1 = FrameBuffer_1.FrameBuffer.create([edlCalcTex1]); const edlCalcFbo2 = FrameBuffer_1.FrameBuffer.create([edlCalcTex2]); const edlCalcFbo4 = FrameBuffer_1.FrameBuffer.create([edlCalcTex4]); const edlFiltFbo2 = FrameBuffer_1.FrameBuffer.create([edlFiltTex2]); const edlFiltFbo4 = FrameBuffer_1.FrameBuffer.create([edlFiltTex4]); if (undefined === edlCalcFbo1 || undefined === edlCalcFbo2 || undefined === edlCalcFbo4 || undefined === edlFiltFbo2 || undefined === edlFiltFbo4) { (0, core_bentley_1.dispose)(edlCalcFbo1); (0, core_bentley_1.dispose)(edlCalcFbo2); (0, core_bentley_1.dispose)(edlCalcFbo4); (0, core_bentley_1.dispose)(edlFiltFbo2); (0, core_bentley_1.dispose)(edlFiltFbo4); return undefined; } return new Bundle(edlCalcTex1, edlCalcTex2, edlCalcTex4, edlFiltTex2, edlFiltTex4, edlCalcFbo1, edlCalcFbo2, edlCalcFbo4, edlFiltFbo2, edlFiltFbo4); } get isDisposed() { return undefined === this.edlCalcTex1 && undefined === this.edlCalcTex2 && undefined === this.edlCalcTex4 && undefined === this.edlFiltTex2 && undefined === this.edlFiltTex4 && undefined === this.edlCalcFbo1 && undefined === this.edlCalcFbo2 && undefined === this.edlCalcFbo4 && undefined === this.edlFiltFbo2 && undefined === this.edlFiltFbo4 && undefined === this.edlCalcBasicGeom && undefined === this.edlCalcFullGeom?.[0] && undefined === this.edlCalcFullGeom?.[1] && undefined === this.edlCalcFullGeom?.[2] && undefined === this.edlCalcFullGeom && undefined === this.edlFiltGeom?.[0] && undefined === this.edlFiltGeom?.[1] && undefined === this.edlFiltGeom && undefined === this.edlMixGeom; } [Symbol.dispose]() { this.edlCalcTex1 = (0, core_bentley_1.dispose)(this.edlCalcTex1); this.edlCalcTex2 = (0, core_bentley_1.dispose)(this.edlCalcTex2); this.edlCalcTex4 = (0, core_bentley_1.dispose)(this.edlCalcTex4); this.edlFiltTex2 = (0, core_bentley_1.dispose)(this.edlFiltTex2); this.edlFiltTex4 = (0, core_bentley_1.dispose)(this.edlFiltTex4); this.edlCalcFbo1 = (0, core_bentley_1.dispose)(this.edlCalcFbo1); this.edlCalcFbo2 = (0, core_bentley_1.dispose)(this.edlCalcFbo2); this.edlCalcFbo4 = (0, core_bentley_1.dispose)(this.edlCalcFbo4); this.edlFiltFbo2 = (0, core_bentley_1.dispose)(this.edlFiltFbo2); this.edlFiltFbo4 = (0, core_bentley_1.dispose)(this.edlFiltFbo4); this.edlCalcBasicGeom = (0, core_bentley_1.dispose)(this.edlCalcBasicGeom); if (this.edlCalcFullGeom) { this.edlCalcFullGeom[0] = (0, core_bentley_1.dispose)(this.edlCalcFullGeom?.[0]); this.edlCalcFullGeom[1] = (0, core_bentley_1.dispose)(this.edlCalcFullGeom?.[1]); this.edlCalcFullGeom[2] = (0, core_bentley_1.dispose)(this.edlCalcFullGeom?.[2]); this.edlCalcFullGeom = undefined; } if (this.edlFiltGeom) { this.edlFiltGeom[0] = (0, core_bentley_1.dispose)(this.edlFiltGeom?.[0]); this.edlFiltGeom[1] = (0, core_bentley_1.dispose)(this.edlFiltGeom?.[1]); this.edlFiltGeom = undefined; } this.edlMixGeom = (0, core_bentley_1.dispose)(this.edlMixGeom); } } /** @internal */ var EDLMode; (function (EDLMode) { EDLMode[EDLMode["Off"] = 0] = "Off"; EDLMode[EDLMode["On"] = 1] = "On"; EDLMode[EDLMode["Full"] = 2] = "Full"; })(EDLMode || (exports.EDLMode = EDLMode = {})); class EyeDomeLighting { _bundle; _width; _height; _depth; // depth buffer to read from, has to be non-MS and be up to date in draw if MS is used _edlFinalFbo; _edlFinalBufs; _target; getBundle() { if (undefined === this._bundle) { this._bundle = Bundle.create(this._width, this._height); (0, core_bentley_1.assert)(undefined !== this._bundle); } return this._bundle; } constructor(target) { this._target = target; this._width = target.viewRect.width; this._height = target.viewRect.height; } init(width, height, depth) { this._width = width; this._height = height; this._depth = depth; // don't create buffers until we know we will use them (first draw) return true; } collectStatistics(stats) { const bundle = this._bundle; if (undefined !== bundle) { (0, SceneCompositor_1.collectTextureStatistics)(bundle.edlCalcTex1, stats); (0, SceneCompositor_1.collectTextureStatistics)(bundle.edlCalcTex2, stats); (0, SceneCompositor_1.collectTextureStatistics)(bundle.edlCalcTex4, stats); (0, SceneCompositor_1.collectTextureStatistics)(bundle.edlFiltTex2, stats); (0, SceneCompositor_1.collectTextureStatistics)(bundle.edlFiltTex4, stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlCalcBasicGeom, stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlCalcFullGeom?.[0], stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlCalcFullGeom?.[1], stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlCalcFullGeom?.[2], stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlFiltGeom?.[0], stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlFiltGeom?.[1], stats); (0, SceneCompositor_1.collectGeometryStatistics)(bundle.edlMixGeom, stats); } } get isDisposed() { return undefined === this._bundle && undefined === this._edlFinalFbo; } [Symbol.dispose]() { this._bundle = (0, core_bentley_1.dispose)(this._bundle); this._edlFinalFbo = (0, core_bentley_1.dispose)(this._edlFinalFbo); } reset() { this[Symbol.dispose](); } /** calculate EyeDomeLighting at specified quality using screen space shaders * returns true if succeeds */ draw(edlParams) { if (undefined === edlParams.inputTex || undefined === this._depth || undefined === edlParams.curFbo) return false; const bundle = this.getBundle(); if (undefined === bundle) return false; // NB: have to test and create MS buffer as well if useMsBuffers, not outputting to depth const finalBufs = edlParams.curFbo.getColorTargets(edlParams.useMsBuffers, 0); if (undefined === this._edlFinalFbo || this._edlFinalBufs?.tex !== finalBufs.tex || (edlParams.useMsBuffers && this._edlFinalBufs?.msBuf !== finalBufs.msBuf)) { this._edlFinalFbo = (0, core_bentley_1.dispose)(this._edlFinalFbo); this._edlFinalBufs = finalBufs; const filters = [GL_1.GL.MultiSampling.Filter.Linear]; this._edlFinalFbo = FrameBuffer_1.FrameBuffer.create([this._edlFinalBufs.tex], undefined, edlParams.useMsBuffers && this._edlFinalBufs.msBuf ? [this._edlFinalBufs.msBuf] : undefined, filters, undefined); if (undefined === this._edlFinalFbo) return false; } const fbStack = System_1.System.instance.frameBufferStack; const useMsBuffers = edlParams.useMsBuffers; System_1.System.instance.applyRenderState(RenderState_1.RenderState.defaults); // ###TODO: should radius be (optionally?) voxel based instead of pixel here? if (edlParams.edlMode === EDLMode.On) { // draw using single pass version (still 8 samples, full size) fbStack.execute(this._edlFinalFbo, true, useMsBuffers, () => { if (bundle.edlCalcBasicGeom === undefined) { const ct1 = edlParams.inputTex; const ctd = (0, core_bentley_1.expectDefined)(this._depth?.getHandle()); bundle.edlCalcBasicGeom = CachedGeometry_1.EDLCalcBasicGeometry.createGeometry((0, core_bentley_1.expectDefined)(ct1.getHandle()), ctd, ct1.width, ct1.height); } const params = (0, ScratchDrawParams_1.getDrawParams)(this._target, (0, core_bentley_1.expectDefined)(bundle.edlCalcBasicGeom)); this._target.techniques.draw(params); }); } else { // EDLMode.Full // draw with full method based on original paper using full, 1/2, and 1/4 sizes const edlCalc2FB = [(0, core_bentley_1.expectDefined)(bundle.edlCalcFbo1), (0, core_bentley_1.expectDefined)(bundle.edlCalcFbo2), (0, core_bentley_1.expectDefined)(bundle.edlCalcFbo4)]; if (bundle.edlCalcFullGeom === undefined) { const ct1 = edlParams.inputTex; const ct2 = bundle.edlCalcTex2; const ct4 = bundle.edlCalcTex4; const ctd = (0, core_bentley_1.expectDefined)(this._depth?.getHandle()); bundle.edlCalcFullGeom = [CachedGeometry_1.EDLCalcFullGeometry.createGeometry((0, core_bentley_1.expectDefined)(ct1.getHandle()), ctd, 1, ct1.width, ct1.height), CachedGeometry_1.EDLCalcFullGeometry.createGeometry((0, core_bentley_1.expectDefined)(ct1.getHandle()), ctd, 2, (0, core_bentley_1.expectDefined)(ct2?.width), (0, core_bentley_1.expectDefined)(ct2?.height)), CachedGeometry_1.EDLCalcFullGeometry.createGeometry((0, core_bentley_1.expectDefined)(ct1.getHandle()), ctd, 4, (0, core_bentley_1.expectDefined)(ct4?.width), (0, core_bentley_1.expectDefined)(ct4?.height))]; } const edlFiltFbos = [(0, core_bentley_1.expectDefined)(bundle.edlFiltFbo2), (0, core_bentley_1.expectDefined)(bundle.edlFiltFbo4)]; if (bundle.edlFiltGeom === undefined) { const ft2 = bundle.edlCalcTex2; const ft4 = bundle.edlCalcTex4; const ftd = (0, core_bentley_1.expectDefined)(this._depth?.getHandle()); bundle.edlFiltGeom = [CachedGeometry_1.EDLFilterGeometry.createGeometry((0, core_bentley_1.expectDefined)(ft2?.getHandle()), ftd, 2, (0, core_bentley_1.expectDefined)(ft2?.width), (0, core_bentley_1.expectDefined)(ft2?.height)), CachedGeometry_1.EDLFilterGeometry.createGeometry((0, core_bentley_1.expectDefined)(ft4?.getHandle()), ftd, 4, (0, core_bentley_1.expectDefined)(ft4?.width), (0, core_bentley_1.expectDefined)(ft4?.height))]; } const gl = System_1.System.instance.context; // Loop through the 3 sizes calculating an edl buffer, and if not first size, then optionally filtering those for (let i = 0; i < 3; ++i) { fbStack.execute(edlCalc2FB[i], true, false, () => { const colTex = edlCalc2FB[i].getColor(0); gl.viewport(0, 0, colTex.width, colTex.height); // have to set viewport to current texture size const params = (0, ScratchDrawParams_1.getDrawParams)(this._target, (0, core_bentley_1.expectDefined)(bundle.edlCalcFullGeom?.[i])); this._target.techniques.draw(params); }); if (edlParams.edlFilter && i > 0) { fbStack.execute(edlFiltFbos[i - 1], true, false, () => { const params = (0, ScratchDrawParams_1.getDrawParams)(this._target, (0, core_bentley_1.expectDefined)(bundle.edlFiltGeom?.[i - 1])); this._target.techniques.draw(params); }); } } gl.viewport(0, 0, this._width, this._height); // Restore viewport // Now combine the 3 results and output const tex1 = (0, core_bentley_1.expectDefined)(bundle.edlCalcTex1?.getHandle()); const tex2 = (0, core_bentley_1.expectDefined)(edlParams.edlFilter ? bundle.edlFiltTex2?.getHandle() : bundle.edlCalcTex2?.getHandle()); const tex4 = (0, core_bentley_1.expectDefined)(edlParams.edlFilter ? bundle.edlFiltTex4?.getHandle() : bundle.edlCalcTex4?.getHandle()); fbStack.execute(this._edlFinalFbo, true, useMsBuffers, () => { if (bundle.edlMixGeom === undefined) { bundle.edlMixGeom = CachedGeometry_1.EDLMixGeometry.createGeometry(tex1, tex2, tex4); } else { if (bundle.edlMixGeom.colorTexture1 !== tex1 || bundle.edlMixGeom.colorTexture2 !== tex2 || bundle.edlMixGeom.colorTexture4 !== tex4) { (0, core_bentley_1.dispose)(bundle.edlMixGeom); bundle.edlMixGeom = CachedGeometry_1.EDLMixGeometry.createGeometry(tex1, tex2, tex4); } } const params = (0, ScratchDrawParams_1.getDrawParams)(this._target, (0, core_bentley_1.expectDefined)(bundle.edlMixGeom)); this._target.techniques.draw(params); }); } return true; } } exports.EyeDomeLighting = EyeDomeLighting; //# sourceMappingURL=EDL.js.map