/** * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { QuadSchema, QuadValues } from '../../mol-gl/compute/util'; import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable'; import { TextureSpec, UniformSpec, DefineSpec, Values } from '../../mol-gl/renderable/schema'; import { ShaderCode } from '../../mol-gl/shader-code'; import { WebGLContext } from '../../mol-gl/webgl/context'; import { createComputeRenderItem } from '../../mol-gl/webgl/render-item'; import { Texture } from '../../mol-gl/webgl/texture'; import { Vec2 } from '../../mol-math/linear-algebra'; import { ValueCell } from '../../mol-util'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { quad_vert } from '../../mol-gl/shader/quad.vert'; import { fxaa_frag } from '../../mol-gl/shader/fxaa.frag'; import { Viewport } from '../camera/util'; import { RenderTarget } from '../../mol-gl/webgl/render-target'; export const FxaaParams = { edgeThresholdMin: PD.Numeric(0.0312, { min: 0.0312, max: 0.0833, step: 0.0001 }, { description: 'Trims the algorithm from processing darks.' }), edgeThresholdMax: PD.Numeric(0.063, { min: 0.063, max: 0.333, step: 0.001 }, { description: 'The minimum amount of local contrast required to apply algorithm.' }), iterations: PD.Numeric(12, { min: 0, max: 16, step: 1 }, { description: 'Number of edge exploration steps.' }), subpixelQuality: PD.Numeric(0.30, { min: 0.00, max: 1.00, step: 0.01 }, { description: 'Choose the amount of sub-pixel aliasing removal.' }), }; export type FxaaProps = PD.Values export class FxaaPass { private readonly renderable: FxaaRenderable constructor(private webgl: WebGLContext, input: Texture) { this.renderable = getFxaaRenderable(webgl, input); } private updateState(viewport: Viewport) { const { gl, state } = this.webgl; state.enable(gl.SCISSOR_TEST); state.disable(gl.BLEND); state.disable(gl.DEPTH_TEST); state.depthMask(false); const { x, y, width, height } = viewport; gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); state.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); } setSize(width: number, height: number) { ValueCell.update(this.renderable.values.uTexSizeInv, Vec2.set(this.renderable.values.uTexSizeInv.ref.value, 1 / width, 1 / height)); } update(input: Texture, props: FxaaProps) { const { values } = this.renderable; const { edgeThresholdMin, edgeThresholdMax, iterations, subpixelQuality } = props; let needsUpdate = false; if (values.tColor.ref.value !== input) { ValueCell.update(this.renderable.values.tColor, input); needsUpdate = true; } if (values.dEdgeThresholdMin.ref.value !== edgeThresholdMin) needsUpdate = true; ValueCell.updateIfChanged(values.dEdgeThresholdMin, edgeThresholdMin); if (values.dEdgeThresholdMax.ref.value !== edgeThresholdMax) needsUpdate = true; ValueCell.updateIfChanged(values.dEdgeThresholdMax, edgeThresholdMax); if (values.dIterations.ref.value !== iterations) needsUpdate = true; ValueCell.updateIfChanged(values.dIterations, iterations); if (values.dSubpixelQuality.ref.value !== subpixelQuality) needsUpdate = true; ValueCell.updateIfChanged(values.dSubpixelQuality, subpixelQuality); if (needsUpdate) { this.renderable.update(); } } render(viewport: Viewport, target: RenderTarget | undefined) { if (target) { target.bind(); } else { this.webgl.unbindFramebuffer(); } this.updateState(viewport); this.renderable.render(); } } // const FxaaSchema = { ...QuadSchema, tColor: TextureSpec('texture', 'rgba', 'ubyte', 'linear'), uTexSizeInv: UniformSpec('v2'), dEdgeThresholdMin: DefineSpec('number'), dEdgeThresholdMax: DefineSpec('number'), dIterations: DefineSpec('number'), dSubpixelQuality: DefineSpec('number'), }; const FxaaShaderCode = ShaderCode('fxaa', quad_vert, fxaa_frag); type FxaaRenderable = ComputeRenderable> function getFxaaRenderable(ctx: WebGLContext, colorTexture: Texture): FxaaRenderable { const width = colorTexture.getWidth(); const height = colorTexture.getHeight(); const values: Values = { ...QuadValues, tColor: ValueCell.create(colorTexture), uTexSizeInv: ValueCell.create(Vec2.create(1 / width, 1 / height)), dEdgeThresholdMin: ValueCell.create(0.0312), dEdgeThresholdMax: ValueCell.create(0.125), dIterations: ValueCell.create(12), dSubpixelQuality: ValueCell.create(0.3), }; const schema = { ...FxaaSchema }; const renderItem = createComputeRenderItem(ctx, 'triangles', FxaaShaderCode, schema, values); return createComputeRenderable(renderItem, values); }