WebGL--α混合


α混合

在WebGL中,颜色是通过RGBA四个分量来定义的,其中A指是的颜色透明度(alpha),透明度的范围从0.0到1.0,其中1.0表示完全不透明,0.0表示完全透明。另外,图像绘图区域的颜色也可以通过α来设置:

gl.clearColor(R,G,B,α)

当α为0时,整个绘图的背景色是白色的,即canvas后网页本来的颜色。

混合(blending)或α混合(alpha blending)指的就是有透明度的颜色和其背后的颜色所混合在一起所产生的新的颜色的效果。

实际上在渲染管线对片元处理步骤的中,已经包含了混合这一处理过程。在WebGL中使用它只需要开启它即可。

gl.enable(gl.BLEND);

gl.blendFunc(src_factor, dst_factor);

1.开启混合功能

gl.enable(gl.BLEND);

我们通过gl.enable()函数来指定WebGL开启相对应的功能。在这里,我们需要使用到颜色混合功能,故参数为gl.BLEND

注意,这里记录的仅仅是WebGL相关API的实现,背后的图形学知识等我学到了就会记录ψ(`?′)ψ

这样我们就开启了相关功能。

2.设置混合参数

gl.blendFunc(src_factor, dst_factor);

介绍函数之前,先要对该函数涉及到的参数进行介绍:

在颜色混合当中,最基本的情况下就是涉及到两个颜色的混合,并且复杂的颜色混合也可以归结到两个颜色的混合。WebGL进行颜色混合时,涉及到两个颜色,一个称为源颜色(source color)和目标颜色(destination color)。

源颜色可以理解为一个画板上的最基本的初始调色颜色,目标颜色就是要混进初始调色颜色颜色。(需要将后者(目标颜色)混入前者(源颜色中))。在WebGL上的体现可以理解为先画的物体的颜色为源颜色,后画的物体的颜色就是目标颜色,通过颜色混合使这两个颜色按照一定的方式计算出新的颜色,并最终将这个新的颜色作为两个颜色混合之后的终极颜色呈现出来。

下面介绍混合函数:

ConstantFactorDescription
gl.ZERO 0,0,0,0 所有颜色乘0.
gl.ONE 1,1,1,1 所有颜色乘1.
gl.SRC_COLOR RS, GS, BS, AS 将所有颜色乘上源颜色.
gl.ONE_MINUS_SRC_COLOR 1-RS, 1-GS, 1-BS, 1-AS 每个源颜色所有颜色乘1 .
gl.DST_COLOR RD, GD, BD, AD 将所有颜色与目标颜色相乘.
gl.ONE_MINUS_DST_COLOR 1-RD, 1-GD, 1-BD, 1-AD 将所有颜色乘以1减去每个目标颜色.
gl.SRC_ALPHA AS, AS, AS, AS 将所有颜色乘以源alpha值.
gl.ONE_MINUS_SRC_ALPHA 1-AS, 1-AS, 1-AS, 1-AS 将所有颜色乘以1 减去源alpha值.
gl.DST_ALPHA AD, AD, AD, AD 将所有颜色与目标alpha值相乘.
gl.ONE_MINUS_DST_ALPHA 1-AD, 1-AD, 1-AD, 1-AD 将所有颜色乘以1减去目标alpha值.
gl.SRC_ALPHA_SATURATE min(AS, 1 - AD), min(AS, 1 - AD), min(AS, 1 - AD), 1 将RGB颜色乘以源alpha值或1减去目标alpha值中的较小值。alpha值乘以1.
     
     
     
   

 

 引自(https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/blendFunc),有些参数WebGL已经移除,故不列在表格当中

其中S表示源颜色,D表示目标颜色,R G B A 分别表示红,绿,蓝和透明度。

混合颜色的公式可以这样描述: <混合后颜色> = <源颜色> * src_factor + <目标颜色> * dst_factor


例如:源颜色是半透明的绿色(0.0,1.0,0.0,0.4),而目标颜色是完全不透明的黄色(1.0,1.0,0.0,1.0),对应的参数为gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA

那么颜色的计算就是(0.0,1.0,0.0)*(0.4,0.4,0.4) + (1.0,1.0,0.0)*(0.6,0.6,0.6)-->(0.6,1.0,0.0)

计算的颜色公式依赖于参数,有时候参数是四个分量,有时候是三个分量,计算时要注意要不要加上透明度。

参数的默认值是(sfactor)gl.ZERO和(dfactor)gl.ONE。(实验的效果是只有背景色了,图形颜色全没了...)

只要开启blend功能,不管你图像颜色的透明度是不是1.0,根据参数的选择,它可能会有影响也可能没有影响。

颜色的混合方式有很多:比如有一种称为加法混合的混合方式,它通常会产生爆炸的光照效果,因此会用于任务提示等场景中。

示例:

//vertex shader
var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'attribute vec4 a_Color;\n' +
    'uniform mat4 u_MvpMatrix;\n' +
    'varying vec4 v_Color;\n' +
    'void main() {\n' +
    'gl_Position = u_MvpMatrix * a_Position;\n' +
    'v_Color = a_Color;\n' +
    '}\n';

// fragment shdaer
var FSHADER_SOURCE =
   'precision mediump float;\n' +
    'varying vec4 v_Color;\n' +
    'void main() {\n' +
    'gl_FragColor = v_Color;\n' +
    "}\n";


let gl, canvas, n;
function main() {
    canvas = document.getElementById('webgl');

    if (!canvas) {
        console.log('failed to get canvas');
    }

    gl = getWebGLContext(canvas);
    if (!gl) {
        console.log('failed to get gl');
    }

    initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);

    //设置可视空间
    var mvpMatrix = new Matrix4();

    var u_MvpMatirx = gl.getUniformLocation(gl.program, 'u_MvpMatrix');

    mvpMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);

    mvpMatrix.lookAt(0, 0, 6, 0, 0, -1, 0, 1, 0);

    gl.uniformMatrix4fv(u_MvpMatirx, false, mvpMatrix.elements);

    //设置缓冲区
     n = initVertexBuffer(gl);


     rending(gl)
    

}

function rending(gl) {
    //背景色
    gl.clearColor(0.0, 0.0, 0.0, 0.5);

    //开启深度检测
    gl.enable(gl.DEPTH_TEST);

    //开启颜色混合
    gl.enable(gl.BLEND);

    //指定混合参数
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    //清除颜色缓冲区 深度缓冲区

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    //绘制
    gl.drawArrays(gl.TRIANGLES, 0, n);
}

function initVertexBuffer(gl) {


      var position = new Float32Array([
          //
        -0.5, 1.0, -4.0, 0.4, 1.0, 0.4, 0.5,
        -1.25, -1.0, -4.0, 0.4, 1.0, 0.4, 0.5,
        -0.25, -1.0, -4.0, 1.0, 0.4, 0.4, 0.5,

        //
        -0.5, 1.0, -2.0, 1.0, 1.0, 0.4,0.5, 
        -1.25, -1.0, -2.0, 1.0, 1.0, 0.4,0.5,
        -0.25, -1.0, -2.0, 1.0, 0.4, 0.4, 0.5,

         //
        -0.75, 1.0, 0.0, 0.4, 0.4, 1.0, 0.5,  
        -1.25, -1.0, 0.0, 0.4, 0.4, 1.0, 0.5,
        -0.25, -1.0, 0.0, 1.0, 0.4, 0.4, 0.5
      ]);

      var SIZE = position.BYTES_PER_ELEMENT;

      var n = 9;

      //创建缓冲区
      var vertBuffer = gl.createBuffer();

      gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);

      gl.bufferData(gl.ARRAY_BUFFER, position, gl.STATIC_DRAW);

        //传递顶点
        var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
        gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, SIZE * 7, 0);

        gl.enableVertexAttribArray(a_Position);

        //传递颜色
        var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
        gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, SIZE * 7, SIZE * 3);

        gl.enableVertexAttribArray(a_Color);

        return n;

}

注:以上为JS代码,其中用到的一些函数库来源于WebGL编程指南

顶点位置不能瞎改,尤其是设置了可视空间之后,稍微改一下就看不到图了,甚至连背景颜色都不给你看!!

还有,当开启α混合功能时,背景颜色也会和图像的颜色产生混合,也就是说原先的图形的颜色会因为和背景颜色发生混合重新显示出一个新的颜色。

--参考查阅资料:

WebGL编程指南

https://developer.mozilla.org/zh-CN/