Javascript HtmlCanvas+;globalAlpha+;重叠=输出颜色不正确

Javascript HtmlCanvas+;globalAlpha+;重叠=输出颜色不正确,javascript,canvas,opacity,alpha,overlapping,Javascript,Canvas,Opacity,Alpha,Overlapping,我想画一堆几乎透明的白色矩形,它们彼此重叠 每个矩形的不透明度为0.01 我有100个重叠的矩形,我希望输出结果是所有不透明度的总和。换句话说,我希望结果是白色的,没有任何不透明度 但事实并非如此 为什么? 如何得到我想要的结果 下面是一个简单的代码来说明这个问题 let canvas = document.createElement("canvas"); canvas.width = canvas.height = 512; let ctx = canvas.getCon

我想画一堆几乎透明的白色矩形,它们彼此重叠

每个矩形的不透明度为0.01

我有100个重叠的矩形,我希望输出结果是所有不透明度的总和。换句话说,我希望结果是白色的,没有任何不透明度

但事实并非如此

  • 为什么?
  • 如何得到我想要的结果
  • 下面是一个简单的代码来说明这个问题

    let canvas = document.createElement("canvas");
    canvas.width = canvas.height = 512;
    
    let ctx = canvas.getContext("2d");
    ctx.fillStyle = "#000000";
    ctx.fillRect(0,0,512,512);
    
    ctx.fillStyle = "#ffffff";
    ctx.globalAlpha = 0.01;
    
    for(let i=0;i<100;i++){
       let n = i*3;
       ctx.fillRect(n,n,512-n,512-n);
    }
    
    document.body.appendChild(canvas); 
    
    let canvas=document.createElement(“canvas”);
    canvas.width=canvas.height=512;
    设ctx=canvas.getContext(“2d”);
    ctx.fillStyle=“#000000”;
    ctx.fillRect(0,0512512);
    ctx.fillStyle=“#ffffff”;
    ctx.globalAlpha=0.01;
    
    对于(让i=0;i进行两种RGBA颜色的alpha混合(假设正常混合和合成模式),一般公式为

    out = alpha * new + (1 - alpha) * old
    
    但是,
    out
    必须是一个整数(范围为0~255),因此我们必须在其上应用舍入(我猜舍入可能取决于实现以及它们存储颜色值的方式)

    如果我们将
    alpha
    取为0.1,并保持白色,则
    new
    为255(白色为255,255,255),old为0(透明),
    第一步,我们将

    out = round( 0.1 * 255 + (1 - 0.1) * 0 );
    // => 26
    
    out = round( 0.1 * 255 + (1 - 0.1) * 26 );
    // => 49
    out = round( 0.1 * 255 + (1 - 0.1) * 49 );
    // => 70
    out = round( 0.1 * 255 + (1 - 0.1) * 70 );
    // => 89
    [...] // a few iterations later
    // => 250
    out = round( 0.1 * 255 + (1 - 0.1) * 250 );
    // => 251
    out = round( 0.1 * 255 + (1 - 0.1) * 251 );
    // => 251
    out = round( 0.1 * 255 + (1 - 0.1) * 251 );
    // => 251
    
    我们将有以下步骤

    out = round( 0.1 * 255 + (1 - 0.1) * 0 );
    // => 26
    
    out = round( 0.1 * 255 + (1 - 0.1) * 26 );
    // => 49
    out = round( 0.1 * 255 + (1 - 0.1) * 49 );
    // => 70
    out = round( 0.1 * 255 + (1 - 0.1) * 70 );
    // => 89
    [...] // a few iterations later
    // => 250
    out = round( 0.1 * 255 + (1 - 0.1) * 250 );
    // => 251
    out = round( 0.1 * 255 + (1 - 0.1) * 251 );
    // => 251
    out = round( 0.1 * 255 + (1 - 0.1) * 251 );
    // => 251
    
    一旦达到该
    251、251、251
    颜色值,无论要添加多少层,它都不会再改变颜色值,因此,如果该颜色的半透明版本的不透明度小于0.5,则无法通过分层该颜色的半透明版本来达到完全不透明的颜色

    您的
    0.01
    值将需要更多的迭代才能达到此稳定位置(153对38),但它将以较低的值(206)实现



    请注意,颜色通常由其alpha预乘存储,这可能会在这些数字中增加一些舍入错误。

    感谢您的解释。昨天我几乎找到了一个没有任何逻辑的解决方案,只是通过实验(但我更愿意理解我在做什么,所以谢谢您)。我昨天找到的解决方案如下: