I'm rendering circles using regl, and have three goals:
- The canvas should be transparent, showing HTML content behind it.
- Circles should be antialiased smoothly.
- Overlapping circles should look reasonable (blend colors, no corners showing)
So far, I have this: Glitch code and demo.
UPDATE: The demo links now reflect the working, accepted answer. Code below is unchanged.
index.js
const regl = require('regl');
const glsl = require('glslify');
const vertexShader = glsl.file('../shaders/vertex.glsl');
const fragmentShader = glsl.file('../shaders/fragment.glsl');
// Create webgl context and clear.
const canvasEl = document.querySelector('canvas');
const app = regl({
canvas: canvasEl,
extensions: ['OES_standard_derivatives']
});
app.clear({color: [0, 0, 0, 0], depth: 1});
// Generate random points and colors.
const attributes = {position: [], color: []};
for (let i = 0; i < 100; i++) {
attributes.position.push(Math.random() * 2 - 1, Math.random() * 2 - 1);
attributes.color.push(Math.random(), Math.random(), Math.random());
}
// Define draw instructions.
const draw = app({
vert: vertexShader,
frag: fragmentShader,
attributes: attributes,
count: 100,
primitive: 'points',
depth: {enable: true},
blend: {
enable: true
}
});
// Draw the points.
draw();
vertex.glsl
// vertex.glsl
precision mediump float;
attribute vec2 position;
attribute vec3 color;
varying vec3 vColor;
void main() {
vColor = color;
gl_Position = vec4(position, 0, 1);
gl_PointSize = 40.;
}
fragment.glsl
// fragment.glsl
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec3 vColor;
void main() {
float r = 0.0, delta = 0.0, alpha = 1.0;
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
r = dot(cxy, cxy);
#ifdef GL_OES_standard_derivatives
delta = fwidth(r);
alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
#endif
gl_FragColor = vec4(vColor, alpha);
}
However, the result looks not-so-great. Corners are visible, and circles aren't blending properly.
I've also tried adding the following blend terms:
func: {
srcRGB: 'src alpha',
srcAlpha: 'one minus src alpha',
dstRGB: 'one minus src alpha',
dstAlpha: 'src alpha'
}
This looks a bit better, but the corners are still there and something is wrong when the background is white.
Could you suggest improvements to this? (And maybe point me to better information about blending, if that's what I'm missing here) Thanks!
You should set up your blending parameters like this:
This means that your destination and source color become blended like this:
Red, green and blue (
srcRGB: 'src alpha'
,dstRGB: 'one minus src alpha'
):The alpha channel (
srcAlpha: 'src alpha'
,dstAlpha: 'one minus src alpha'
):seel also glBlendFunc and glBlendFuncSeparate
Further you have to make sure that the depth test is disabled
See the WebGL example above (tested with Firefox, Chrome, Edge, Opera):