UNPKG

molstar

Version:

A comprehensive macromolecular library.

275 lines 14.4 kB
"use strict"; /** * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiSampleHelper = exports.MultiSamplePass = exports.MultiSampleParams = void 0; var tslib_1 = require("tslib"); var util_1 = require("../../mol-gl/compute/util"); var schema_1 = require("../../mol-gl/renderable/schema"); var mol_util_1 = require("../../mol-util"); var linear_algebra_1 = require("../../mol-math/linear-algebra"); var shader_code_1 = require("../../mol-gl/shader-code"); var render_item_1 = require("../../mol-gl/webgl/render-item"); var renderable_1 = require("../../mol-gl/renderable"); var param_definition_1 = require("../../mol-util/param-definition"); var camera_1 = require("../../mol-canvas3d/camera"); var quad_vert_1 = require("../../mol-gl/shader/quad.vert"); var compose_frag_1 = require("../../mol-gl/shader/compose.frag"); var ComposeSchema = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, util_1.QuadSchema), { tColor: (0, schema_1.TextureSpec)('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: (0, schema_1.UniformSpec)('v2'), uWeight: (0, schema_1.UniformSpec)('f') }); var ComposeShaderCode = (0, shader_code_1.ShaderCode)('compose', quad_vert_1.quad_vert, compose_frag_1.compose_frag); function getComposeRenderable(ctx, colorTexture) { var values = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, util_1.QuadValues), { tColor: mol_util_1.ValueCell.create(colorTexture), uTexSize: mol_util_1.ValueCell.create(linear_algebra_1.Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())), uWeight: mol_util_1.ValueCell.create(1.0) }); var schema = (0, tslib_1.__assign)({}, ComposeSchema); var renderItem = (0, render_item_1.createComputeRenderItem)(ctx, 'triangles', ComposeShaderCode, schema, values); return (0, renderable_1.createComputeRenderable)(renderItem, values); } exports.MultiSampleParams = { mode: param_definition_1.ParamDefinition.Select('off', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]), sampleLevel: param_definition_1.ParamDefinition.Numeric(2, { min: 0, max: 5, step: 1 }), }; var MultiSamplePass = /** @class */ (function () { function MultiSamplePass(webgl, drawPass) { this.webgl = webgl; this.drawPass = drawPass; var _a = webgl.extensions, colorBufferFloat = _a.colorBufferFloat, textureFloat = _a.textureFloat, colorBufferHalfFloat = _a.colorBufferHalfFloat, textureHalfFloat = _a.textureHalfFloat; var width = drawPass.colorTarget.getWidth(); var height = drawPass.colorTarget.getHeight(); this.colorTarget = webgl.createRenderTarget(width, height, false); var type = colorBufferHalfFloat && textureHalfFloat ? 'fp16' : colorBufferFloat && textureFloat ? 'float32' : 'uint8'; this.composeTarget = webgl.createRenderTarget(width, height, false, type); this.holdTarget = webgl.createRenderTarget(width, height, false); this.compose = getComposeRenderable(webgl, drawPass.colorTarget.texture); } MultiSamplePass.isEnabled = function (props) { return props.mode !== 'off'; }; MultiSamplePass.prototype.syncSize = function () { var width = this.drawPass.colorTarget.getWidth(); var height = this.drawPass.colorTarget.getHeight(); var _a = this.compose.values.uTexSize.ref.value, w = _a[0], h = _a[1]; if (width !== w || height !== h) { this.colorTarget.setSize(width, height); this.composeTarget.setSize(width, height); this.holdTarget.setSize(width, height); mol_util_1.ValueCell.update(this.compose.values.uTexSize, linear_algebra_1.Vec2.set(this.compose.values.uTexSize.ref.value, width, height)); } }; MultiSamplePass.prototype.render = function (sampleIndex, renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props) { if (props.multiSample.mode === 'temporal') { return this.renderTemporalMultiSample(sampleIndex, renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props); } else { this.renderMultiSample(renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props); return sampleIndex; } }; MultiSamplePass.prototype.bindOutputTarget = function (toDrawingBuffer) { if (toDrawingBuffer) { this.webgl.unbindFramebuffer(); } else { this.colorTarget.bind(); } }; MultiSamplePass.prototype.renderMultiSample = function (renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props) { var _a = this, compose = _a.compose, composeTarget = _a.composeTarget, drawPass = _a.drawPass, webgl = _a.webgl; var gl = webgl.gl, state = webgl.state; // based on the Multisample Anti-Aliasing Render Pass // contributed to three.js by bhouston / http://clara.io/ // // This manual approach to MSAA re-renders the scene once for // each sample with camera jitter and accumulates the results. var offsetList = JitterVectors[Math.max(0, Math.min(props.multiSample.sampleLevel, 5))]; var _b = camera.viewport, x = _b.x, y = _b.y, width = _b.width, height = _b.height; var baseSampleWeight = 1.0 / offsetList.length; var roundingRange = 1 / 32; camera.viewOffset.enabled = true; mol_util_1.ValueCell.update(compose.values.tColor, drawPass.getColorTarget(props.postprocessing).texture); compose.update(); // render the scene multiple times, each slightly jitter offset // from the last and accumulate the results. for (var i = 0; i < offsetList.length; ++i) { var offset = offsetList[i]; camera_1.Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height); camera.update(); // the theory is that equal weights for each sample lead to an accumulation of rounding // errors. The following equation varies the sampleWeight per sample so that it is uniformly // distributed across a range of values whose rounding errors cancel each other out. var uniformCenteredDistribution = -0.5 + (i + 0.5) / offsetList.length; var sampleWeight = baseSampleWeight + roundingRange * uniformCenteredDistribution; mol_util_1.ValueCell.update(compose.values.uWeight, sampleWeight); // render scene drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking); // compose rendered scene with compose target composeTarget.bind(); state.enable(gl.BLEND); state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE); state.disable(gl.DEPTH_TEST); state.depthMask(false); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); if (i === 0) { state.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); } compose.render(); } mol_util_1.ValueCell.update(compose.values.uWeight, 1.0); mol_util_1.ValueCell.update(compose.values.tColor, composeTarget.texture); compose.update(); this.bindOutputTarget(toDrawingBuffer); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); state.disable(gl.BLEND); compose.render(); camera.viewOffset.enabled = false; camera.update(); }; MultiSamplePass.prototype.renderTemporalMultiSample = function (sampleIndex, renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props) { var _a = this, compose = _a.compose, composeTarget = _a.composeTarget, holdTarget = _a.holdTarget, drawPass = _a.drawPass, webgl = _a.webgl; var gl = webgl.gl, state = webgl.state; // based on the Multisample Anti-Aliasing Render Pass // contributed to three.js by bhouston / http://clara.io/ // // This manual approach to MSAA re-renders the scene once for // each sample with camera jitter and accumulates the results. var offsetList = JitterVectors[Math.max(0, Math.min(props.multiSample.sampleLevel, 5))]; if (sampleIndex === -2 || sampleIndex >= offsetList.length) return -2; var _b = camera.viewport, x = _b.x, y = _b.y, width = _b.width, height = _b.height; var sampleWeight = 1.0 / offsetList.length; if (sampleIndex === -1) { drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking); mol_util_1.ValueCell.update(compose.values.uWeight, 1.0); mol_util_1.ValueCell.update(compose.values.tColor, drawPass.getColorTarget(props.postprocessing).texture); compose.update(); holdTarget.bind(); state.disable(gl.BLEND); state.disable(gl.DEPTH_TEST); state.depthMask(false); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); compose.render(); sampleIndex += 1; } else { camera.viewOffset.enabled = true; mol_util_1.ValueCell.update(compose.values.tColor, drawPass.getColorTarget(props.postprocessing).texture); mol_util_1.ValueCell.update(compose.values.uWeight, sampleWeight); compose.update(); // render the scene multiple times, each slightly jitter offset // from the last and accumulate the results. var numSamplesPerFrame = Math.pow(2, Math.max(0, props.multiSample.sampleLevel - 2)); for (var i = 0; i < numSamplesPerFrame; ++i) { var offset = offsetList[sampleIndex]; camera_1.Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height); camera.update(); // render scene drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking); // compose rendered scene with compose target composeTarget.bind(); state.enable(gl.BLEND); state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE); state.disable(gl.DEPTH_TEST); state.depthMask(false); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); if (sampleIndex === 0) { state.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); } compose.render(); sampleIndex += 1; if (sampleIndex >= offsetList.length) break; } } this.bindOutputTarget(toDrawingBuffer); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); var accumulationWeight = sampleIndex * sampleWeight; if (accumulationWeight > 0) { mol_util_1.ValueCell.update(compose.values.uWeight, 1.0); mol_util_1.ValueCell.update(compose.values.tColor, composeTarget.texture); compose.update(); state.disable(gl.BLEND); compose.render(); } if (accumulationWeight < 1.0) { mol_util_1.ValueCell.update(compose.values.uWeight, 1.0 - accumulationWeight); mol_util_1.ValueCell.update(compose.values.tColor, holdTarget.texture); compose.update(); if (accumulationWeight === 0) state.disable(gl.BLEND); else state.enable(gl.BLEND); compose.render(); } camera.viewOffset.enabled = false; camera.update(); return sampleIndex >= offsetList.length ? -2 : sampleIndex; }; return MultiSamplePass; }()); exports.MultiSamplePass = MultiSamplePass; var JitterVectors = [ [ [0, 0] ], [ [4, 4], [-4, -4] ], [ [-2, -6], [6, -2], [-6, 2], [2, 6] ], [ [1, -3], [-1, 3], [5, 1], [-3, -5], [-5, 5], [-7, -1], [3, 7], [7, -7] ], [ [1, 1], [-1, -3], [-3, 2], [4, -1], [-5, -2], [2, 5], [5, 3], [3, -5], [-2, 6], [0, -7], [-4, -6], [-6, 4], [-8, 0], [7, -4], [6, 7], [-7, -8] ], [ [-4, -7], [-7, -5], [-3, -5], [-5, -4], [-1, -4], [-2, -2], [-6, -1], [-4, 0], [-7, 1], [-1, 2], [-6, 3], [-3, 3], [-7, 6], [-3, 6], [-5, 7], [-1, 7], [5, -7], [1, -6], [6, -5], [4, -4], [2, -3], [7, -2], [1, -1], [4, -1], [2, 1], [6, 2], [0, 4], [4, 4], [2, 5], [7, 5], [5, 6], [3, 7] ] ]; JitterVectors.forEach(function (offsetList) { offsetList.forEach(function (offset) { // 0.0625 = 1 / 16 offset[0] *= 0.0625; offset[1] *= 0.0625; }); }); var MultiSampleHelper = /** @class */ (function () { function MultiSampleHelper(multiSamplePass) { this.multiSamplePass = multiSamplePass; this.sampleIndex = -2; } MultiSampleHelper.prototype.update = function (changed, props) { if (changed) this.sampleIndex = -1; return props.mode === 'temporal' ? this.sampleIndex !== -2 : false; }; MultiSampleHelper.prototype.render = function (renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props) { this.sampleIndex = this.multiSamplePass.render(this.sampleIndex, renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props); }; return MultiSampleHelper; }()); exports.MultiSampleHelper = MultiSampleHelper; //# sourceMappingURL=multi-sample.js.map