Add dithering
This commit is contained in:
parent
e4ee421628
commit
b355132861
3 changed files with 42 additions and 4 deletions
|
|
@ -51,6 +51,7 @@ export class RendererImplementation implements Renderer {
|
||||||
private _canvasSize: vec2;
|
private _canvasSize: vec2;
|
||||||
private blendFactor!: number;
|
private blendFactor!: number;
|
||||||
private canvasResizeObserver!: ResizeObserver;
|
private canvasResizeObserver!: ResizeObserver;
|
||||||
|
private frameIndex = 0;
|
||||||
|
|
||||||
private applyRuntimeSettings: {
|
private applyRuntimeSettings: {
|
||||||
[key in keyof RuntimeSettings]: (value: any) => void;
|
[key in keyof RuntimeSettings]: (value: any) => void;
|
||||||
|
|
@ -247,6 +248,18 @@ export class RendererImplementation implements Renderer {
|
||||||
|
|
||||||
distanceNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()),
|
distanceNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()),
|
||||||
shadingNdcPixelSize: 2 / Math.max(...this.lightingFrameBuffer.getSize()),
|
shadingNdcPixelSize: 2 / Math.max(...this.lightingFrameBuffer.getSize()),
|
||||||
|
|
||||||
|
// The motion-blur blend multiplies the lights pass' output by
|
||||||
|
// blendFactor before it reaches the 8-bit canvas, which would attenuate
|
||||||
|
// the anti-banding dither below the quantization step it has to mask.
|
||||||
|
// Pre-scale the dither to arrive at full strength after blending; the
|
||||||
|
// clamp keeps extreme motion-blur values from injecting visible grain.
|
||||||
|
ditherStrength: lightsSizeChanged ? 1 : 1 / Math.max(this.blendFactor, 0.125),
|
||||||
|
|
||||||
|
// Scroll the dither pattern every frame (golden-ratio offset), so the
|
||||||
|
// motion-blur blend averages independently dithered frames instead of
|
||||||
|
// freezing into a banded fixed point.
|
||||||
|
ditherSeed: (this.frameIndex = (this.frameIndex + 1) & 63) * 5.588238,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.distancePass.render(this.uniformsProvider.getUniforms(common), [
|
this.distancePass.render(this.uniformsProvider.getUniforms(common), [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
#version 100
|
#version 100
|
||||||
|
|
||||||
precision lowp float;
|
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||||
|
precision highp float;
|
||||||
|
#else
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define INTENSITY_INSIDE_RATIO {intensityInsideRatio}
|
#define INTENSITY_INSIDE_RATIO {intensityInsideRatio}
|
||||||
#define SHADOW_TRACE_COUNT {shadowTraceCount}
|
#define SHADOW_TRACE_COUNT {shadowTraceCount}
|
||||||
|
|
@ -11,6 +15,8 @@ precision lowp float;
|
||||||
{macroDefinitions}
|
{macroDefinitions}
|
||||||
|
|
||||||
uniform float shadingNdcPixelSize;
|
uniform float shadingNdcPixelSize;
|
||||||
|
uniform float ditherStrength;
|
||||||
|
uniform float ditherSeed;
|
||||||
uniform vec2 squareToAspectRatioTimes2;
|
uniform vec2 squareToAspectRatioTimes2;
|
||||||
uniform vec3 ambientLight;
|
uniform vec3 ambientLight;
|
||||||
|
|
||||||
|
|
@ -62,6 +68,14 @@ float shadowTransparency(float startingDistance, float lightCenterDistance, vec2
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
float ditherNoise() {
|
||||||
|
float ign = fract(52.9829189 * fract(
|
||||||
|
dot(gl_FragCoord.xy + ditherSeed, vec2(0.06711056, 0.00583715))
|
||||||
|
));
|
||||||
|
float t = 2.0 * ign - 1.0;
|
||||||
|
return sign(t) * (1.0 - sqrt(1.0 - abs(t)));
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 rgbaColorAtPosition;
|
vec4 rgbaColorAtPosition;
|
||||||
float startingDistance = getDistance(uvCoordinates, rgbaColorAtPosition);
|
float startingDistance = getDistance(uvCoordinates, rgbaColorAtPosition);
|
||||||
|
|
@ -144,7 +158,7 @@ void main() {
|
||||||
float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0);
|
float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0);
|
||||||
vec3 antialiasedColor = mix(insideColor, outsideColor, edge);
|
vec3 antialiasedColor = mix(insideColor, outsideColor, edge);
|
||||||
gl_FragColor = vec4(
|
gl_FragColor = vec4(
|
||||||
antialiasedColor,
|
antialiasedColor + ditherNoise() * ditherStrength / 255.0,
|
||||||
rgbaColorAtPosition.a
|
rgbaColorAtPosition.a
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
|
||||||
precision lowp float;
|
precision highp float;
|
||||||
|
precision highp sampler2D;
|
||||||
|
|
||||||
#define INTENSITY_INSIDE_RATIO {intensityInsideRatio}
|
#define INTENSITY_INSIDE_RATIO {intensityInsideRatio}
|
||||||
#define SHADOW_TRACE_COUNT {shadowTraceCount}
|
#define SHADOW_TRACE_COUNT {shadowTraceCount}
|
||||||
|
|
@ -13,6 +14,8 @@ precision lowp float;
|
||||||
|
|
||||||
uniform float shadingNdcPixelSize;
|
uniform float shadingNdcPixelSize;
|
||||||
uniform float distanceNdcPixelSize;
|
uniform float distanceNdcPixelSize;
|
||||||
|
uniform float ditherStrength;
|
||||||
|
uniform float ditherSeed;
|
||||||
uniform vec2 squareToAspectRatioTimes2;
|
uniform vec2 squareToAspectRatioTimes2;
|
||||||
uniform vec3 ambientLight;
|
uniform vec3 ambientLight;
|
||||||
|
|
||||||
|
|
@ -83,6 +86,14 @@ float shadowTransparency(float startingDistance, float lightCenterDistance, vec2
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
float ditherNoise() {
|
||||||
|
float ign = fract(52.9829189 * fract(
|
||||||
|
dot(gl_FragCoord.xy + ditherSeed, vec2(0.06711056, 0.00583715))
|
||||||
|
));
|
||||||
|
float t = 2.0 * ign - 1.0;
|
||||||
|
return sign(t) * (1.0 - sqrt(1.0 - abs(t)));
|
||||||
|
}
|
||||||
|
|
||||||
out vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
void main() {
|
void main() {
|
||||||
vec4 rgbaColorAtPosition = getColor(uvCoordinates);
|
vec4 rgbaColorAtPosition = getColor(uvCoordinates);
|
||||||
|
|
@ -167,7 +178,7 @@ void main() {
|
||||||
float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0);
|
float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0);
|
||||||
vec3 antialiasedColor = mix(insideColor, outsideColor, edge);
|
vec3 antialiasedColor = mix(insideColor, outsideColor, edge);
|
||||||
fragmentColor = vec4(
|
fragmentColor = vec4(
|
||||||
antialiasedColor,
|
antialiasedColor + ditherNoise() * ditherStrength / 255.0,
|
||||||
rgbaColorAtPosition.a
|
rgbaColorAtPosition.a
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue