UNPKG

molstar

Version:

A comprehensive macromolecular library.

427 lines (426 loc) 28.6 kB
/** * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz> */ import { __assign } from "tslib"; import { createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util'; import { TextureSpec, UniformSpec, DefineSpec } from '../../mol-gl/renderable/schema'; import { ShaderCode } from '../../mol-gl/shader-code'; import { ValueCell } from '../../mol-util'; import { createComputeRenderItem } from '../../mol-gl/webgl/render-item'; import { createComputeRenderable } from '../../mol-gl/renderable'; import { Mat4, Vec2, Vec3, Vec4 } from '../../mol-math/linear-algebra'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { quad_vert } from '../../mol-gl/shader/quad.vert'; import { outlines_frag } from '../../mol-gl/shader/outlines.frag'; import { ssao_frag } from '../../mol-gl/shader/ssao.frag'; import { ssaoBlur_frag } from '../../mol-gl/shader/ssao-blur.frag'; import { postprocessing_frag } from '../../mol-gl/shader/postprocessing.frag'; import { Color } from '../../mol-util/color'; import { FxaaParams, FxaaPass } from './fxaa'; import { SmaaParams, SmaaPass } from './smaa'; import { isTimingMode } from '../../mol-util/debug'; import { BackgroundParams, BackgroundPass } from './background'; var OutlinesSchema = __assign(__assign({}, QuadSchema), { tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: UniformSpec('v2'), dOrthographic: DefineSpec('number'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), uMaxPossibleViewZDiff: UniformSpec('f') }); function getOutlinesRenderable(ctx, depthTextureOpaque, depthTextureTransparent) { var width = depthTextureOpaque.getWidth(); var height = depthTextureOpaque.getHeight(); var values = __assign(__assign({}, QuadValues), { tDepthOpaque: ValueCell.create(depthTextureOpaque), tDepthTransparent: ValueCell.create(depthTextureTransparent), uTexSize: ValueCell.create(Vec2.create(width, height)), dOrthographic: ValueCell.create(0), uNear: ValueCell.create(1), uFar: ValueCell.create(10000), uMaxPossibleViewZDiff: ValueCell.create(0.5) }); var schema = __assign({}, OutlinesSchema); var shaderCode = ShaderCode('outlines', quad_vert, outlines_frag); var renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); return createComputeRenderable(renderItem, values); } var SsaoSchema = __assign(__assign({}, QuadSchema), { tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uSamples: UniformSpec('v3[]'), dNSamples: DefineSpec('number'), uProjection: UniformSpec('m4'), uInvProjection: UniformSpec('m4'), uBounds: UniformSpec('v4'), uTexSize: UniformSpec('v2'), uRadius: UniformSpec('f'), uBias: UniformSpec('f') }); function getSsaoRenderable(ctx, depthTexture) { var values = __assign(__assign({}, QuadValues), { tDepth: ValueCell.create(depthTexture), uSamples: ValueCell.create(getSamples(32)), dNSamples: ValueCell.create(32), uProjection: ValueCell.create(Mat4.identity()), uInvProjection: ValueCell.create(Mat4.identity()), uBounds: ValueCell.create(Vec4()), uTexSize: ValueCell.create(Vec2.create(ctx.gl.drawingBufferWidth, ctx.gl.drawingBufferHeight)), uRadius: ValueCell.create(8.0), uBias: ValueCell.create(0.025) }); var schema = __assign({}, SsaoSchema); var shaderCode = ShaderCode('ssao', quad_vert, ssao_frag); var renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); return createComputeRenderable(renderItem, values); } var SsaoBlurSchema = __assign(__assign({}, QuadSchema), { tSsaoDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: UniformSpec('v2'), uKernel: UniformSpec('f[]'), dOcclusionKernelSize: DefineSpec('number'), uBlurDirectionX: UniformSpec('f'), uBlurDirectionY: UniformSpec('f'), uMaxPossibleViewZDiff: UniformSpec('f'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), uBounds: UniformSpec('v4'), dOrthographic: DefineSpec('number') }); function getSsaoBlurRenderable(ctx, ssaoDepthTexture, direction) { var values = __assign(__assign({}, QuadValues), { tSsaoDepth: ValueCell.create(ssaoDepthTexture), uTexSize: ValueCell.create(Vec2.create(ssaoDepthTexture.getWidth(), ssaoDepthTexture.getHeight())), uKernel: ValueCell.create(getBlurKernel(15)), dOcclusionKernelSize: ValueCell.create(15), uBlurDirectionX: ValueCell.create(direction === 'horizontal' ? 1 : 0), uBlurDirectionY: ValueCell.create(direction === 'vertical' ? 1 : 0), uMaxPossibleViewZDiff: ValueCell.create(0.5), uNear: ValueCell.create(0.0), uFar: ValueCell.create(10000.0), uBounds: ValueCell.create(Vec4()), dOrthographic: ValueCell.create(0) }); var schema = __assign({}, SsaoBlurSchema); var shaderCode = ShaderCode('ssao_blur', quad_vert, ssaoBlur_frag); var renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); return createComputeRenderable(renderItem, values); } function getBlurKernel(kernelSize) { var sigma = kernelSize / 3.0; var halfKernelSize = Math.floor((kernelSize + 1) / 2); var kernel = []; for (var x = 0; x < halfKernelSize; x++) { kernel.push((1.0 / ((Math.sqrt(2 * Math.PI)) * sigma)) * Math.exp(-x * x / (2 * sigma * sigma))); } return kernel; } var RandomHemisphereVector = []; for (var i = 0; i < 256; i++) { var v = Vec3(); v[0] = Math.random() * 2.0 - 1.0; v[1] = Math.random() * 2.0 - 1.0; v[2] = Math.random(); Vec3.normalize(v, v); Vec3.scale(v, v, Math.random()); RandomHemisphereVector.push(v); } function getSamples(nSamples) { var samples = []; for (var i = 0; i < nSamples; i++) { var scale = (i * i + 2.0 * i + 1) / (nSamples * nSamples); scale = 0.1 + scale * (1.0 - 0.1); samples.push(RandomHemisphereVector[i][0] * scale); samples.push(RandomHemisphereVector[i][1] * scale); samples.push(RandomHemisphereVector[i][2] * scale); } return samples; } var PostprocessingSchema = __assign(__assign({}, QuadSchema), { tSsaoDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: UniformSpec('v2'), dOrthographic: DefineSpec('number'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), uFogNear: UniformSpec('f'), uFogFar: UniformSpec('f'), uFogColor: UniformSpec('v3'), uOutlineColor: UniformSpec('v3'), uTransparentBackground: UniformSpec('b'), uMaxPossibleViewZDiff: UniformSpec('f'), dOcclusionEnable: DefineSpec('boolean'), uOcclusionOffset: UniformSpec('v2'), dOutlineEnable: DefineSpec('boolean'), dOutlineScale: DefineSpec('number'), uOutlineThreshold: UniformSpec('f') }); function getPostprocessingRenderable(ctx, colorTexture, depthTextureOpaque, depthTextureTransparent, outlinesTexture, ssaoDepthTexture) { var values = __assign(__assign({}, QuadValues), { tSsaoDepth: ValueCell.create(ssaoDepthTexture), tColor: ValueCell.create(colorTexture), tDepthOpaque: ValueCell.create(depthTextureOpaque), tDepthTransparent: ValueCell.create(depthTextureTransparent), tOutlines: ValueCell.create(outlinesTexture), uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())), dOrthographic: ValueCell.create(0), uNear: ValueCell.create(1), uFar: ValueCell.create(10000), uFogNear: ValueCell.create(10000), uFogFar: ValueCell.create(10000), uFogColor: ValueCell.create(Vec3.create(1, 1, 1)), uOutlineColor: ValueCell.create(Vec3.create(0, 0, 0)), uTransparentBackground: ValueCell.create(false), uMaxPossibleViewZDiff: ValueCell.create(0.5), dOcclusionEnable: ValueCell.create(true), uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)), dOutlineEnable: ValueCell.create(false), dOutlineScale: ValueCell.create(1), uOutlineThreshold: ValueCell.create(0.33) }); var schema = __assign({}, PostprocessingSchema); var shaderCode = ShaderCode('postprocessing', quad_vert, postprocessing_frag); var renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); return createComputeRenderable(renderItem, values); } export var PostprocessingParams = { occlusion: PD.MappedStatic('on', { on: PD.Group({ samples: PD.Numeric(32, { min: 1, max: 256, step: 1 }), radius: PD.Numeric(5, { min: 0, max: 10, step: 0.1 }, { description: 'Final occlusion radius is 2^x' }), bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }), blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }), resolutionScale: PD.Numeric(1, { min: 0.1, max: 1, step: 0.05 }, { description: 'Adjust resolution of occlusion calculation' }), }), off: PD.Group({}) }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), outline: PD.MappedStatic('off', { on: PD.Group({ scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }), threshold: PD.Numeric(0.33, { min: 0.01, max: 1, step: 0.01 }), color: PD.Color(Color(0x000000)), }), off: PD.Group({}) }, { cycle: true, description: 'Draw outline around 3D objects' }), antialiasing: PD.MappedStatic('smaa', { fxaa: PD.Group(FxaaParams), smaa: PD.Group(SmaaParams), off: PD.Group({}) }, { options: [['fxaa', 'FXAA'], ['smaa', 'SMAA'], ['off', 'Off']], description: 'Smooth pixel edges' }), background: PD.Group(BackgroundParams, { isFlat: true }), }; var PostprocessingPass = /** @class */ (function () { function PostprocessingPass(webgl, assetManager, drawPass) { this.webgl = webgl; this.drawPass = drawPass; this.bgColor = Vec3(); this.occlusionOffset = [0, 0]; this.transparentBackground = false; var colorTarget = drawPass.colorTarget, depthTextureTransparent = drawPass.depthTextureTransparent, depthTextureOpaque = drawPass.depthTextureOpaque; var width = colorTarget.getWidth(); var height = colorTarget.getHeight(); this.nSamples = 1; this.blurKernelSize = 1; this.downsampleFactor = 1; this.ssaoScale = this.calcSsaoScale(); // needs to be linear for anti-aliasing pass this.target = webgl.createRenderTarget(width, height, false, 'uint8', 'linear'); this.outlinesTarget = webgl.createRenderTarget(width, height, false); this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent); this.ssaoFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurSecondPassFramebuffer = webgl.resources.framebuffer(); var sw = Math.floor(width * this.ssaoScale); var sh = Math.floor(height * this.ssaoScale); this.downsampledDepthTarget = webgl.createRenderTarget(sw, sh, false, 'uint8', 'linear'); this.downsampleDepthRenderable = createCopyRenderable(webgl, depthTextureOpaque); this.ssaoDepthTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'linear'); this.ssaoDepthTexture.define(sw, sh); this.ssaoDepthTexture.attachFramebuffer(this.ssaoFramebuffer, 'color0'); this.ssaoDepthBlurProxyTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'linear'); this.ssaoDepthBlurProxyTexture.define(sw, sh); this.ssaoDepthBlurProxyTexture.attachFramebuffer(this.ssaoBlurFirstPassFramebuffer, 'color0'); this.ssaoDepthTexture.attachFramebuffer(this.ssaoBlurSecondPassFramebuffer, 'color0'); this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture); this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal'); this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical'); this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture); this.background = new BackgroundPass(webgl, assetManager, width, height); } PostprocessingPass.isEnabled = function (props) { return props.occlusion.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off'; }; PostprocessingPass.isOutlineEnabled = function (props) { return props.outline.name === 'on'; }; PostprocessingPass.prototype.calcSsaoScale = function () { // downscale ssao for high pixel-ratios return Math.min(1, 1 / this.webgl.pixelRatio) * this.downsampleFactor; }; PostprocessingPass.prototype.setSize = function (width, height) { var _a = this.renderable.values.uTexSize.ref.value, w = _a[0], h = _a[1]; var ssaoScale = this.calcSsaoScale(); if (width !== w || height !== h || this.ssaoScale !== ssaoScale) { this.ssaoScale = ssaoScale; var sw = Math.floor(width * this.ssaoScale); var sh = Math.floor(height * this.ssaoScale); this.target.setSize(width, height); this.outlinesTarget.setSize(width, height); this.downsampledDepthTarget.setSize(sw, sh); this.ssaoDepthTexture.define(sw, sh); this.ssaoDepthBlurProxyTexture.define(sw, sh); ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.outlinesRenderable.values.uTexSize, Vec2.set(this.outlinesRenderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh)); this.background.setSize(width, height); } }; PostprocessingPass.prototype.updateState = function (camera, transparentBackground, backgroundColor, props) { var needsUpdateMain = false; var needsUpdateSsao = false; var needsUpdateSsaoBlur = false; var orthographic = camera.state.mode === 'orthographic' ? 1 : 0; var outlinesEnabled = props.outline.name === 'on'; var occlusionEnabled = props.occlusion.name === 'on'; var invProjection = Mat4.identity(); Mat4.invert(invProjection, camera.projection); if (props.occlusion.name === 'on') { ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection); ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection); var _a = this.renderable.values.uTexSize.ref.value, w = _a[0], h = _a[1]; var b = this.ssaoRenderable.values.uBounds; var v = camera.viewport; var s = this.ssaoScale; Vec4.set(b.ref.value, Math.floor(v.x * s) / (w * s), Math.floor(v.y * s) / (h * s), Math.ceil((v.x + v.width) * s) / (w * s), Math.ceil((v.y + v.height) * s) / (h * s)); ValueCell.update(b, b.ref.value); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uBounds, b.ref.value); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uBounds, b.ref.value); ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.uFar, camera.far); ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.uFar, camera.far); if (this.ssaoBlurFirstPassRenderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateSsaoBlur = true; } ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOrthographic, orthographic); ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOrthographic, orthographic); if (this.nSamples !== props.occlusion.params.samples) { needsUpdateSsao = true; this.nSamples = props.occlusion.params.samples; ValueCell.update(this.ssaoRenderable.values.uSamples, getSamples(this.nSamples)); ValueCell.updateIfChanged(this.ssaoRenderable.values.dNSamples, this.nSamples); } ValueCell.updateIfChanged(this.ssaoRenderable.values.uRadius, Math.pow(2, props.occlusion.params.radius)); ValueCell.updateIfChanged(this.ssaoRenderable.values.uBias, props.occlusion.params.bias); if (this.blurKernelSize !== props.occlusion.params.blurKernelSize) { needsUpdateSsaoBlur = true; this.blurKernelSize = props.occlusion.params.blurKernelSize; var kernel = getBlurKernel(this.blurKernelSize); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uKernel, kernel); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uKernel, kernel); ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); } if (this.downsampleFactor !== props.occlusion.params.resolutionScale) { needsUpdateSsao = true; this.downsampleFactor = props.occlusion.params.resolutionScale; this.ssaoScale = this.calcSsaoScale(); var sw = Math.floor(w * this.ssaoScale); var sh = Math.floor(h * this.ssaoScale); this.downsampledDepthTarget.setSize(sw, sh); this.ssaoDepthTexture.define(sw, sh); this.ssaoDepthBlurProxyTexture.define(sw, sh); if (this.ssaoScale === 1) { ValueCell.update(this.ssaoRenderable.values.tDepth, this.drawPass.depthTextureTransparent); } else { ValueCell.update(this.ssaoRenderable.values.tDepth, this.downsampledDepthTarget.texture); } ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh)); } } if (props.outline.name === 'on') { var threshold = props.outline.params.threshold; // orthographic needs lower threshold if (camera.state.mode === 'orthographic') threshold /= 5; var factor = Math.pow(1000, threshold) / 1000; // use radiusMax for stable outlines when zooming var maxPossibleViewZDiff = factor * camera.state.radiusMax; var outlineScale = props.outline.params.scale - 1; ValueCell.updateIfChanged(this.outlinesRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far); ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff); ValueCell.update(this.renderable.values.uOutlineColor, Color.toVec3Normalized(this.renderable.values.uOutlineColor.ref.value, props.outline.params.color)); ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff); if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale); } ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far); ValueCell.updateIfChanged(this.renderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.renderable.values.uFogFar, camera.fogFar); ValueCell.updateIfChanged(this.renderable.values.uFogNear, camera.fogNear); ValueCell.update(this.renderable.values.uFogColor, Color.toVec3Normalized(this.renderable.values.uFogColor.ref.value, backgroundColor)); ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground); if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic); if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled); if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled); if (needsUpdateSsao) { this.ssaoRenderable.update(); } if (needsUpdateSsaoBlur) { this.ssaoBlurFirstPassRenderable.update(); this.ssaoBlurSecondPassRenderable.update(); } if (needsUpdateMain) { this.renderable.update(); } var _b = this.webgl, gl = _b.gl, state = _b.state; state.enable(gl.SCISSOR_TEST); state.disable(gl.BLEND); state.disable(gl.DEPTH_TEST); state.depthMask(false); var _c = camera.viewport, x = _c.x, y = _c.y, width = _c.width, height = _c.height; state.viewport(x, y, width, height); state.scissor(x, y, width, height); }; PostprocessingPass.prototype.setOcclusionOffset = function (x, y) { this.occlusionOffset[0] = x; this.occlusionOffset[1] = y; ValueCell.update(this.renderable.values.uOcclusionOffset, Vec2.set(this.renderable.values.uOcclusionOffset.ref.value, x, y)); }; PostprocessingPass.prototype.setTransparentBackground = function (value) { this.transparentBackground = value; }; PostprocessingPass.prototype.render = function (camera, toDrawingBuffer, transparentBackground, backgroundColor, props) { if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render'); this.updateState(camera, transparentBackground, backgroundColor, props); if (props.outline.name === 'on') { this.outlinesTarget.bind(); this.outlinesRenderable.render(); } // don't render occlusion if offset is given, // which will reuse the existing occlusion if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) { if (this.ssaoScale < 1) { this.downsampledDepthTarget.bind(); this.downsampleDepthRenderable.render(); } this.ssaoFramebuffer.bind(); this.ssaoRenderable.render(); this.ssaoBlurFirstPassFramebuffer.bind(); this.ssaoBlurFirstPassRenderable.render(); this.ssaoBlurSecondPassFramebuffer.bind(); this.ssaoBlurSecondPassRenderable.render(); } if (toDrawingBuffer) { this.webgl.unbindFramebuffer(); } else { this.target.bind(); } var _a = this.webgl, gl = _a.gl, state = _a.state; this.background.update(camera, props.background); if (this.background.isEnabled(props.background)) { if (this.transparentBackground) { state.clearColor(0, 0, 0, 0); } else { Color.toVec3Normalized(this.bgColor, backgroundColor); state.clearColor(this.bgColor[0], this.bgColor[1], this.bgColor[2], 1); } gl.clear(gl.COLOR_BUFFER_BIT); state.enable(gl.BLEND); state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); this.background.render(); } else { state.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); } this.renderable.render(); if (isTimingMode) this.webgl.timer.markEnd('PostprocessingPass.render'); }; return PostprocessingPass; }()); export { PostprocessingPass }; var AntialiasingPass = /** @class */ (function () { function AntialiasingPass(webgl, drawPass) { this.drawPass = drawPass; var colorTarget = drawPass.colorTarget; var width = colorTarget.getWidth(); var height = colorTarget.getHeight(); this.target = webgl.createRenderTarget(width, height, false); this.fxaa = new FxaaPass(webgl, this.target.texture); this.smaa = new SmaaPass(webgl, this.target.texture); } AntialiasingPass.isEnabled = function (props) { return props.antialiasing.name !== 'off'; }; AntialiasingPass.prototype.setSize = function (width, height) { var w = this.target.texture.getWidth(); var h = this.target.texture.getHeight(); if (width !== w || height !== h) { this.target.setSize(width, height); this.fxaa.setSize(width, height); if (this.smaa.supported) this.smaa.setSize(width, height); } }; AntialiasingPass.prototype._renderFxaa = function (camera, toDrawingBuffer, props) { if (props.antialiasing.name !== 'fxaa') return; var input = PostprocessingPass.isEnabled(props) ? this.drawPass.postprocessing.target.texture : this.drawPass.colorTarget.texture; this.fxaa.update(input, props.antialiasing.params); this.fxaa.render(camera.viewport, toDrawingBuffer ? undefined : this.target); }; AntialiasingPass.prototype._renderSmaa = function (camera, toDrawingBuffer, props) { if (props.antialiasing.name !== 'smaa') return; var input = PostprocessingPass.isEnabled(props) ? this.drawPass.postprocessing.target.texture : this.drawPass.colorTarget.texture; this.smaa.update(input, props.antialiasing.params); this.smaa.render(camera.viewport, toDrawingBuffer ? undefined : this.target); }; AntialiasingPass.prototype.render = function (camera, toDrawingBuffer, props) { if (props.antialiasing.name === 'off') return; if (props.antialiasing.name === 'fxaa') { this._renderFxaa(camera, toDrawingBuffer, props); } else if (props.antialiasing.name === 'smaa') { if (!this.smaa.supported) { throw new Error('SMAA not supported, missing "HTMLImageElement"'); } this._renderSmaa(camera, toDrawingBuffer, props); } }; return AntialiasingPass; }()); export { AntialiasingPass };