le but de cette page est d'expliquer l'importance du "premultiplied alpha" en WebGL.

on a un fichier au format PNG. il contient une image comportant des zones plus ou moins transparentes.

cliquez sur l'image pour la télécharger :

Nous allons d'abord observer cette image de diverses façons

Voici cette image chargée dans le logiciel Pinta

la zone façon petit carrelage représente la transparence

On ajoute un calque au dessous . On le rempli avec la couleur noire.

Plaçons cette image comme élément d'une balise <img> (avec un fond noir)
<img src="particle.png" style="background-color:black" >

Enfin avec du code WebGL



oups....mais y a un problème !

voyons le code JavaScriopt, WebGL et GLSL



  







let images=[];

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.crossOrigin = 'anonymous';
    img.src = url;
  });
}

async function loadImages(imgs) {
  images = await Promise.all(imgs.map(loadImage));
}

async function main() {
  await loadImages([
       'uneParticle.png'
  ]);

    let vertex=`
    attribute vec2 position;
    void main() {
      gl_Position = vec4(position,0, 1);
      gl_PointSize = 256.0;
    }
  `;
  let fragment=`
    precision highp float;
    uniform sampler2D particle;
    void main() {
      vec4 color= texture2D(particle, gl_PointCoord);

      gl_FragColor=color;
    }
  `;
  go1("glcanvas1",vertex,fragment);

   fragment=`
    precision highp float;
    uniform sampler2D particle;
    void main() {
      vec4 color= texture2D(particle, gl_PointCoord);

    color.rgb = vec3(color.r * color.a, color.g * color.a , color.b * color.a);

      gl_FragColor=color;
    }
  `;
  go1("glcanvas2",vertex,fragment);


}





main();




function go1(leCanvas,vertex,fragment) {


  const canvas = document.getElementById(leCanvas);
  canvas.width=256;
  canvas.height=256;
  const gl = canvas.getContext("webgl");

  let program = gl.createProgram();
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(vertexShader, vertex);
  gl.shaderSource(fragmentShader, fragment);
  gl.compileShader(vertexShader);
  gl.compileShader(fragmentShader);
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  gl.useProgram(program);

  let aPosition = gl.getAttribLocation(program,"position");
  gl.enableVertexAttribArray(aPosition);


  let particleLoc = gl.getUniformLocation(program,"particle");

  let buffer= gl.createBuffer();
  
  gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
 
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array(
      [
        -0.0, 0.0,
        //+0.5, 0.0
      ]
    ),
    gl.STATIC_DRAW
  );


  gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false ,0,0);



  let imageTexture = gl.createTexture();

  let texUnitIndex= 3;
  gl.activeTexture(gl.TEXTURE0 + texUnitIndex);
  const bindPoint = gl.TEXTURE_2D;
  gl.bindTexture(bindPoint, imageTexture);

 

  gl.uniform1i(particleLoc, texUnitIndex);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, images[0]);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

  gl.enable(gl.BLEND);
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  gl.clearColor(0,0,0,1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.POINTS, 0, 1);





  



    }


    function duplicateCanvas(e) {
      let image = new Image();
      image.onload = function() {
        let div  = document.getElementById(e);
        div.appendChild(image);
      }
      image.src = glcanvas.toDataURL('image/png');
    }

    function duplicateCanvas2(source,destination) {
      let image = new Image();
      image.onload = function() {
        let div  = document.getElementById(destination);
        div.appendChild(image);
      }
      image.src = source.toDataURL('image/png');
    }






















...problème résolu en ajoutant cette ligne dans le fragment shader :

color.rgb = vec3(color.r * color.a, color.g * color.a , color.b * color.a);

buffer 2