Skip to content
Snippets Groups Projects
Commit 58bc6722 authored by Alexander Rose's avatar Alexander Rose
Browse files

moved fxaa to separate pass

parent 1acfed32
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
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';
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<typeof FxaaParams>
export class FxaaPass {
private readonly renderable: FxaaRenderable
constructor(webgl: WebGLContext, input: Texture) {
this.renderable = getFxaaRenderable(webgl, input);
}
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() {
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<Values<typeof FxaaSchema>>
function getFxaaRenderable(ctx: WebGLContext, colorTexture: Texture): FxaaRenderable {
const width = colorTexture.getWidth();
const height = colorTexture.getHeight();
const values: Values<typeof FxaaSchema> = {
...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);
}
\ No newline at end of file
...@@ -19,8 +19,8 @@ import { DrawPass } from './draw'; ...@@ -19,8 +19,8 @@ import { DrawPass } from './draw';
import { Camera, ICamera } from '../../mol-canvas3d/camera'; import { Camera, ICamera } from '../../mol-canvas3d/camera';
import quad_vert from '../../mol-gl/shader/quad.vert'; import quad_vert from '../../mol-gl/shader/quad.vert';
import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag'; import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag';
import fxaa_frag from '../../mol-gl/shader/fxaa.frag';
import { StereoCamera } from '../camera/stereo'; import { StereoCamera } from '../camera/stereo';
import { FxaaParams, FxaaPass } from './fxaa';
const PostprocessingSchema = { const PostprocessingSchema = {
...QuadSchema, ...QuadSchema,
...@@ -97,27 +97,22 @@ export const PostprocessingParams = { ...@@ -97,27 +97,22 @@ export const PostprocessingParams = {
off: PD.Group({}) off: PD.Group({})
}, { cycle: true, description: 'Draw outline around 3D objects' }), }, { cycle: true, description: 'Draw outline around 3D objects' }),
antialiasing: PD.MappedStatic('on', { antialiasing: PD.MappedStatic('on', {
on: PD.Group({ on: PD.Group(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: 32, 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.' }),
}),
off: PD.Group({}) off: PD.Group({})
}, { cycle: true, description: 'Fast Approximate Anti-Aliasing (FXAA)' }), }, { cycle: true, description: 'Smooth pixel edges' }),
}; };
export type PostprocessingProps = PD.Values<typeof PostprocessingParams> export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
export class PostprocessingPass { export class PostprocessingPass {
static isEnabled(props: PostprocessingProps) { static isEnabled(props: PostprocessingProps) {
return props.occlusion.name === 'on' || props.outline.name === 'on' || props.antialiasing.name === 'on'; return props.occlusion.name === 'on' || props.outline.name === 'on' || props.antialiasing.name !== 'off';
} }
readonly target: RenderTarget readonly target: RenderTarget
private readonly tmpTarget: RenderTarget private readonly tmpTarget: RenderTarget
private readonly renderable: PostprocessingRenderable private readonly renderable: PostprocessingRenderable
private readonly fxaa: FxaaRenderable private readonly fxaa: FxaaPass
constructor(private webgl: WebGLContext, private drawPass: DrawPass) { constructor(private webgl: WebGLContext, private drawPass: DrawPass) {
const { colorTarget, depthTexture } = drawPass; const { colorTarget, depthTexture } = drawPass;
...@@ -127,7 +122,7 @@ export class PostprocessingPass { ...@@ -127,7 +122,7 @@ export class PostprocessingPass {
this.target = webgl.createRenderTarget(width, height, false); this.target = webgl.createRenderTarget(width, height, false);
this.tmpTarget = webgl.createRenderTarget(width, height, false, 'uint8', 'linear'); this.tmpTarget = webgl.createRenderTarget(width, height, false, 'uint8', 'linear');
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTexture); this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTexture);
this.fxaa = getFxaaRenderable(webgl, this.tmpTarget.texture); this.fxaa = new FxaaPass(webgl, this.tmpTarget.texture);
} }
syncSize() { syncSize() {
...@@ -139,7 +134,7 @@ export class PostprocessingPass { ...@@ -139,7 +134,7 @@ export class PostprocessingPass {
this.target.setSize(width, height); this.target.setSize(width, height);
this.tmpTarget.setSize(width, height); this.tmpTarget.setSize(width, height);
ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
ValueCell.update(this.fxaa.values.uTexSizeInv, Vec2.set(this.fxaa.values.uTexSizeInv.ref.value, 1 / width, 1 / height)); this.fxaa.setSize(width, height);
} }
} }
...@@ -196,7 +191,7 @@ export class PostprocessingPass { ...@@ -196,7 +191,7 @@ export class PostprocessingPass {
this.renderable.update(); this.renderable.update();
} }
if (props.antialiasing.name === 'on') { if (props.antialiasing.name !== 'off') {
this.tmpTarget.bind(); this.tmpTarget.bind();
} else if (toDrawingBuffer) { } else if (toDrawingBuffer) {
this.webgl.unbindFramebuffer(); this.webgl.unbindFramebuffer();
...@@ -209,32 +204,11 @@ export class PostprocessingPass { ...@@ -209,32 +204,11 @@ export class PostprocessingPass {
} }
private _renderFxaa(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) { private _renderFxaa(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) {
if (props.antialiasing.name === 'off') return; if (props.antialiasing.name !== 'on') return;
const { values } = this.fxaa;
let needsUpdate = false;
const input = (props.occlusion.name === 'on' || props.outline.name === 'on') const input = (props.occlusion.name === 'on' || props.outline.name === 'on')
? this.tmpTarget.texture : this.drawPass.colorTarget.texture; ? this.tmpTarget.texture : this.drawPass.colorTarget.texture;
if (values.tColor.ref.value !== input) { this.fxaa.update(input, props.antialiasing.params);
ValueCell.update(this.fxaa.values.tColor, input);
needsUpdate = true;
}
const { edgeThresholdMin, edgeThresholdMax, iterations, subpixelQuality } = props.antialiasing.params;
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.fxaa.update();
}
if (toDrawingBuffer) { if (toDrawingBuffer) {
this.webgl.unbindFramebuffer(); this.webgl.unbindFramebuffer();
...@@ -266,38 +240,3 @@ export class PostprocessingPass { ...@@ -266,38 +240,3 @@ export class PostprocessingPass {
} }
} }
//
const FxaaSchema = {
...QuadSchema,
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
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<Values<typeof FxaaSchema>>
function getFxaaRenderable(ctx: WebGLContext, colorTexture: Texture): FxaaRenderable {
const width = colorTexture.getWidth();
const height = colorTexture.getHeight();
const values: Values<typeof FxaaSchema> = {
...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);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment