From 7d95b744e578e6dc54578db1aeadf04d7cc2ad1d Mon Sep 17 00:00:00 2001 From: Tim Deubler Date: Thu, 27 Jul 2023 16:44:10 +0200 Subject: [PATCH] refactored blending and color masking Signed-off-by: Tim Deubler --- .../display/src/displays/webgl/GLRender.ts | 85 +++++++++---------- .../displays/webgl/buffer/GeometryBuffer.ts | 2 + .../src/displays/webgl/program/DashedLine.ts | 4 +- .../src/displays/webgl/program/Heatmap.ts | 21 ----- .../src/displays/webgl/program/Icon.ts | 5 +- .../src/displays/webgl/program/Program.ts | 38 ++++++--- .../src/displays/webgl/program/Text.ts | 8 +- 7 files changed, 79 insertions(+), 84 deletions(-) diff --git a/packages/display/src/displays/webgl/GLRender.ts b/packages/display/src/displays/webgl/GLRender.ts index 2413374e7..863669af2 100644 --- a/packages/display/src/displays/webgl/GLRender.ts +++ b/packages/display/src/displays/webgl/GLRender.ts @@ -171,6 +171,9 @@ export class GLRender implements BasicRender { stencilTile.pass = PASS.ALPHA; // need to be set to enable stencil test in program init. stencilTile.blend = true; + + stencilTile.colorMask = {r: false, g: false, b: false, a: false}; + this.stencilTile = stencilTile; } @@ -220,14 +223,10 @@ export class GLRender implements BasicRender { if (clearColor) { this.setBackgroundColor(clearColor); } - // gl.clearDepth(1.0); gl.colorMask(true, true, true, true); gl.disable(gl.SCISSOR_TEST); gl.depthMask(true); - - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); - gl.colorMask(true, true, true, false); } init(canvas: HTMLCanvasElement, devicePixelRation: number): void { @@ -548,43 +547,43 @@ export class GLRender implements BasicRender { } - initGroundDepth(x: number, y: number, tileScale?: number - ) { - const gl = this.gl; - const buffer = this.stencilTile; - let program = this.programs[buffer.type]; - - let bufAttributes = buffer.getAttributes(); - program.initBuffers(bufAttributes); - - this.useProgram(program); - - gl.depthRange(0, 1.0); - - gl.depthMask(true); - gl.disable(gl.STENCIL_TEST); - gl.disable(gl.SCISSOR_TEST); - gl.enable(gl.DEPTH_TEST); - - program.initAttributes(bufAttributes); - program.initUniforms(buffer.uniforms); - - const uLocation = program.uniforms; - - gl.uniform2f(uLocation.u_topLeft, x, y); - gl.uniform1f(uLocation.u_tileScale, tileScale || 1); - gl.uniformMatrix4fv(uLocation.u_matrix, false, this.vPMat); - - gl.clear(gl.DEPTH_BUFFER_BIT); - gl.depthFunc(gl.ALWAYS); - // gl.polygonOffset(1, 1); - // gl.enable(gl.POLYGON_OFFSET_FILL); - gl.colorMask(false, false, false, false); - program.draw(buffer); - gl.colorMask(true, true, true, false); - // gl.disable(gl.POLYGON_OFFSET_FILL); - gl.depthFunc(this.depthFnc); - } + // initGroundDepth(x: number, y: number, tileScale?: number + // ) { + // const gl = this.gl; + // const buffer = this.stencilTile; + // let program = this.programs[buffer.type]; + // + // let bufAttributes = buffer.getAttributes(); + // program.initBuffers(bufAttributes); + // + // this.useProgram(program); + // + // gl.depthRange(0, 1.0); + // + // gl.depthMask(true); + // gl.disable(gl.STENCIL_TEST); + // gl.disable(gl.SCISSOR_TEST); + // gl.enable(gl.DEPTH_TEST); + // + // program.initAttributes(bufAttributes); + // program.initUniforms(buffer.uniforms); + // + // const uLocation = program.uniforms; + // + // gl.uniform2f(uLocation.u_topLeft, x, y); + // gl.uniform1f(uLocation.u_tileScale, tileScale || 1); + // gl.uniformMatrix4fv(uLocation.u_matrix, false, this.vPMat); + // + // gl.clear(gl.DEPTH_BUFFER_BIT); + // gl.depthFunc(gl.ALWAYS); + // // gl.polygonOffset(1, 1); + // // gl.enable(gl.POLYGON_OFFSET_FILL); + // gl.colorMask(false, false, false, false); + // program.draw(buffer); + // gl.colorMask(true, true, true, false); + // // gl.disable(gl.POLYGON_OFFSET_FILL); + // gl.depthFunc(this.depthFnc); + // } private drawBuffer( @@ -693,7 +692,7 @@ export class GLRender implements BasicRender { gl.stencilFunc(gl.ALWAYS, refVal, 0xff); gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE); // disable color buffer - gl.colorMask(false, false, false, false); + // gl.colorMask(false, false, false, false); this.drawBuffer(stencilTile, x, y, null, null, this.stencilSize); @@ -701,7 +700,7 @@ export class GLRender implements BasicRender { // disable writing to stencil buffer gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); // enable color buffer again - gl.colorMask(true, true, true, false); + // gl.colorMask(true, true, true, false); } } diff --git a/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts b/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts index ab551860b..0e866cdbd 100644 --- a/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts +++ b/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts @@ -142,6 +142,8 @@ class GeometryBuffer { hitTest?: number; + colorMask?: { r: boolean, g: boolean, b: boolean, a: boolean }; + static fromTemplateBuffer(type: string, templBuffer: TemplateBuffer): GeometryBuffer { const {flexAttributes} = templBuffer; let geoBuffer: GeometryBuffer; diff --git a/packages/display/src/displays/webgl/program/DashedLine.ts b/packages/display/src/displays/webgl/program/DashedLine.ts index e810c9f4e..a84732a09 100644 --- a/packages/display/src/displays/webgl/program/DashedLine.ts +++ b/packages/display/src/displays/webgl/program/DashedLine.ts @@ -44,11 +44,9 @@ class DashedLineProgram extends Program { this.fragmentShaderSrc = fragmentShader; } - initGeometryBuffer(options: GeometryBuffer, pass, stencil: boolean) { + protected blendFunc(sFactor?: number, dFactor?: number) { const {gl} = this; - super.initGeometryBuffer(options, pass, stencil); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - // gl.depthFunc(gl.LESS); } } diff --git a/packages/display/src/displays/webgl/program/Heatmap.ts b/packages/display/src/displays/webgl/program/Heatmap.ts index 4020d0a4d..5c6ab426d 100644 --- a/packages/display/src/displays/webgl/program/Heatmap.ts +++ b/packages/display/src/displays/webgl/program/Heatmap.ts @@ -127,13 +127,9 @@ class HeatmapProgram extends Program { const {width, height} = offscreen.texture; this.bindFramebuffer(offscreen.framebuffer, width, height); - const p = this._pass; - this._pass = PASS.OPAQUE; - gl.blendFunc(gl.ONE, gl.ONE); super.draw(geoBuffer); - this._pass = p; } else { // render offscreen-buffer to screen-buffer and colorize the heatmap. const {offscreenBuffer} = this; @@ -144,27 +140,14 @@ class HeatmapProgram extends Program { this.initGeometryBuffer(offscreenBuffer, PASS.ALPHA, false); this.bindFramebuffer(null); - // this.gl.colorMask(true, true, true, false); - // this.gl.colorMask(true, true, true, false); - // this.gl.colorMask(true, true, true, true); - - // this.gl.disable(this.gl.STENCIL_TEST); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - // this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA); super.draw(offscreenBuffer); - // this.gl.colorMask(true, true, true, false); - // clear offscreen buffer for next frame this.clear(); } this.bindFramebuffer(null); - - gl.disable(gl.BLEND); - gl.colorMask(true, true, true, false); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); } private clear() { @@ -182,11 +165,7 @@ class HeatmapProgram extends Program { // gl.depthMask(true); gl.clear(gl.COLOR_BUFFER_BIT); // gl.colorMask(true, true, true, false); - this.bindFramebuffer(null); - // gl.disable(gl.BLEND); - gl.colorMask(true, true, true, false); - // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); } setResolution(resolution: readonly number[]) { diff --git a/packages/display/src/displays/webgl/program/Icon.ts b/packages/display/src/displays/webgl/program/Icon.ts index 2fdb8368b..04029a145 100644 --- a/packages/display/src/displays/webgl/program/Icon.ts +++ b/packages/display/src/displays/webgl/program/Icon.ts @@ -45,10 +45,9 @@ class IconProgram extends Program { this.fragmentShaderSrc = fragmentShader; } - initGeometryBuffer(options: GeometryBuffer, pass: PASS, stencil: boolean) { + protected blendFunc() { const {gl} = this; - super.initGeometryBuffer(options, pass, stencil); - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + super.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); } } diff --git a/packages/display/src/displays/webgl/program/Program.ts b/packages/display/src/displays/webgl/program/Program.ts index f3a16f436..0ed75912a 100644 --- a/packages/display/src/displays/webgl/program/Program.ts +++ b/packages/display/src/displays/webgl/program/Program.ts @@ -25,12 +25,23 @@ import {ArrayGrp, GeometryBuffer, IndexData, IndexGrp} from '../buffer/GeometryB import {BufferCache} from '../GLRender'; import {Attribute} from '../buffer/Attribute'; import {ConstantAttribute, FlexAttribute} from '../buffer/templates/TemplateBuffer'; +import {DEFAULT_HEATMAP_GRADIENT} from '../buffer/templates/HeatmapBuffer'; let UNDEF; type UniformMap = { [name: string]: WebGLUniformLocation }; type AttributeMap = { [name: string]: Attribute | ConstantAttribute }; +type ColorMask = { r: boolean; g: boolean; b: boolean; a: boolean }; + +const DEFAULT_COLOR_MASK: ColorMask = { + r: true, g: true, b: true, a: false +}; + +const NO_COLOR_MASK: ColorMask = { + r: false, g: false, b: false, a: false +}; + class Program { protected vertexShaderSrc: string; protected fragmentShaderSrc: string; @@ -347,7 +358,6 @@ class Program { draw(geoBuffer: GeometryBuffer) { const {gl} = this; const {groups, instances} = geoBuffer; - const isDepthOnlyPass = this._pass == PASS.ALPHA && geoBuffer.pass & PASS.POST_ALPHA; // console.log( // this.name, @@ -357,11 +367,6 @@ class Program { // 'BLEND', gl.getParameter(gl.BLEND) // ); - if (isDepthOnlyPass) { - // disable color mask for depth/stencil only pass - gl.colorMask(false, false, false, false); - } - for (let grp of groups) { let mode = grp.mode != UNDEF ? grp.mode : this.mode; @@ -392,11 +397,6 @@ class Program { } } } - - if (isDepthOnlyPass) { - // re-enable color mask - gl.colorMask(true, true, true, false); - } }; private setStates(scissor: boolean, blend: boolean, depth: boolean, stencil: boolean) { @@ -427,6 +427,13 @@ class Program { } } + protected blendFunc( + sFactor: number = this.gl.SRC_ALPHA, + dFactor: number = this.gl.ONE_MINUS_SRC_ALPHA + ) { + this.gl.blendFunc(sFactor, dFactor); + } + initGeometryBuffer(geoBuffer: GeometryBuffer, pass: PASS, stencil: boolean, zIndex?: number) { const prog = this; const {gl} = prog; @@ -447,7 +454,7 @@ class Program { } prog.setStates(scissor, blend, depth, stencil && !opaquePass && blend && scissor); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + this.blendFunc(); const cullFace = geoBuffer.cullFace(); @@ -458,6 +465,13 @@ class Program { gl.disable(gl.CULL_FACE); } + const isDepthPrePass = pass == PASS.ALPHA && geoBuffer.pass & PASS.POST_ALPHA; + + const colorMask = isDepthPrePass + ? NO_COLOR_MASK + : geoBuffer.colorMask || DEFAULT_COLOR_MASK; + + gl.colorMask(colorMask.r, colorMask.g, colorMask.b, colorMask.a); // get rid of zfighting for alpha pass. // alpha pass is drawn ordered zindex -> no need to write to depthbuffer (performance) diff --git a/packages/display/src/displays/webgl/program/Text.ts b/packages/display/src/displays/webgl/program/Text.ts index 8c23a1b05..6bf48837f 100644 --- a/packages/display/src/displays/webgl/program/Text.ts +++ b/packages/display/src/displays/webgl/program/Text.ts @@ -43,6 +43,12 @@ class TextProgram extends Program { this.fragmentShaderSrc = fragmentShader; } + + protected blendFunc() { + const {gl} = this; + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + initGeometryBuffer(options: GeometryBuffer, pass: PASS, stencil: boolean, zIndex: number) { const {gl} = this; super.initGeometryBuffer(options, pass, stencil); @@ -51,8 +57,6 @@ class TextProgram extends Program { // this issues is also related to overlapping (atlas.spacing) of characters gl.depthMask(false); // gl.depthFunc(gl.LESS); - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - gl.polygonOffset(0, (1 << 11) * -zIndex); gl.enable(gl.POLYGON_OFFSET_FILL);