block by redblobgames 0bf451ec2fcce6ab8290597f7922fae2

blend-alpha

Full Screen

(redblobgames updated this block to use premultiplied alpha - http://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha.html)

I can’t figure out why points with gl_FragColor = vec4(255, 255, 255, .1); get darker and then lighter when overlaid with increasing density. (note: it should be vec4(1.0, 1.0, 1.0, 0.1) not 0-255 –redblobgames)

I’m using these blending settings:

blend: {
  enable: true,
  func: {
    srcRGB: 'src alpha',
    srcAlpha: 1,
    dstRGB: 'one minus src alpha',
    dstAlpha: 1
  },
  equation: {
    rgb: 'add',
    alpha: 'add'
  },
  color: [0, 0, 0, 0]
},

Tweaking them hasn’t fixed the problem, but I’m not sure what I’m doing…

_script.js

try { window.regltick.cancel() } catch(e){}
console.clear()


var sel = d3.select('#graph').html('')
var c = d3.conventions({sel, layers: 'ds', margin: {left: 30, bottom: 30}, totalHeight: innerHeight})

c.x.domain([0, 1]).range([-1, 1])
c.y.domain([0, 1]).range([-1, 1])

var data = d3.range(100000).map(d => {
  var y = Math.random()
  var x = Math.random()
  var uniform = [
    c.x(x),
    c.y(y),
    1
  ]

  var left = [
    c.x(y*x), 
    c.y(y),
    1
  ]

  return {d, y, uniform, left}

})

c.x.range([0, c.width])
c.y.range([c.height, 0])
d3.drawAxis(c)

reglLib({onDone, container: c.layers[0].node()})


function onDone(err, regl){
  if (err) return console.log(err)
  
  window.regl = regl

  var count = data.length
  var curIndex = 0
  datasets = ['uniform', 'left'].map(str => {
    var pos = data.map(d => d[str])
    return {str, pos}
  })

  const fbo_texture = regl.texture({width: 2*960, height: 2*500, min: 'linear', mag: 'linear'}) // to match the size of the canvas
  const fbo = regl.framebuffer({color: [fbo_texture]})

  var drawPoints = regl({
    vert: `
      precision mediump float;
      attribute vec3 xyz0, xyz1;
      varying float c;
      uniform float interp, radius;      
      void main() {
        vec3 pos = mix(xyz0, xyz1, interp);
        gl_Position = vec4(pos.xy, 0, 1);
        gl_PointSize = radius;
      }`,

    frag: `
      precision mediump float;
      varying float c;
      void main() {
        vec4 color = vec4(1.0, 0.0, 1.0, 0.1);
        gl_FragColor = vec4(color.rgb * color.a, color.a);
      }`,
    attributes: {
      xyz0: () => datasets[curIndex % datasets.length].pos,
      xyz1: () => datasets[(curIndex + 1) % datasets.length].pos
    },
    uniforms: {
      radius: () => 8,
      interp: (ctx, props) => Math.max(0, Math.min(1, props.interp))
    },
    primitive: 'point',
    count: count,
    framebuffer: fbo,

    depth: {
      enable: false
    },
    blend: {
      enable: true,
      func: {
        srcRGB: 'one',
        srcAlpha: 1,
        dstRGB: 'one minus src alpha',
        dstAlpha: 1
      },
      equation: {
        rgb: 'add',
        alpha: 'add'
      },
      color: [0, 0, 0, 0] // only needed for 'constant' blend color
    },

  })

  const demultiply = regl({
    frag: `
        precision mediump float;
        uniform sampler2D u_texture;
        varying vec2 v_uv;
        void main() {
           vec4 premultiplied_color = texture2D(u_texture, v_uv);
           gl_FragColor = premultiplied_color / premultiplied_color.a;
        }`,

    vert: `
        precision highp float;
        attribute vec2 a_uv;
        varying vec2 v_uv;
        void main() {
          v_uv = a_uv;
          gl_Position = vec4(2.0 * v_uv - 1.0, 0.0, 1.0);
        }`,
    
    uniforms:  {
        u_texture: fbo_texture,
    },
    depth: {
        enable: false,
    },
    count: 3,
    attributes: {
        a_uv: [-2, 0, 0, -2, 2, 2]
    },
  })

  var lastSwitchTime = 0
  var switchInterval = 5
  var switchDuration = 5

  window.regltick = regl.frame(({time}) => {
    if ((time - lastSwitchTime) > switchInterval) {
      lastSwitchTime = time
      curIndex = (curIndex + 1) % datasets.length
    }

    fbo.use(() => { regl.clear({color: [1, 1, 1, 0]}) })
    drawPoints({interp: d3.easeBackOut((time - lastSwitchTime) / switchDuration)})
    demultiply()
  })

}


index.html

<!DOCTYPE html>
<html>
<head>
<body>
	<div id='graph'></div>
</body>

<script src='d3+_.js'></script>
<script src='lib-build.js'></script>
<script src='_script.js'></script>
</html>

lib-src.js

var libs = {
  reglLib: require('regl'),
}



for (key in libs) window[key] = libs[key]