@itwin/core-frontend
Version:
iTwin.js frontend components
281 lines • 16.5 kB
JavaScript
"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