WebGL半透明物体的绘制

作者: jeffzhong | 来源:发表于2019-05-02 00:40 被阅读1次

WebGL 中当透明和半透明物体共存时,相关设置不正确的话,物体表面会出现破碎杂乱的断面,非常影响效果,我们接着就来解决这个问题。
完成的展示Demo请看: 半透明物体和透明物体共存

alpha混合

α 混合

让物体实现半透明效果需要用到颜色的α分量。该功能被称为a混合(alpha blending) 或 混合 blending,WebGL已经内置该功能,但需要开启,如果只设置了颜色的第四个分量 α 是看不到透明效果的,这第四分量α其实和 css 样式的 rgba / hsla 颜色模式 中的 α 是一样的,或者类似 opacity 属性。必须要执行下面两个步骤才能看到透明效果:

  1. 开启混合功能:gl.enable(gl.BLEND)。
  2. 指定混合函数:gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)。

gl.blendFunc(src_factor, dst_factor)

a混合函数,指定如如何混合两者的颜色,权重因子的类型多种多样,参数:

  • src_factor: 指定源颜色在混合颜色的权重因子,如下表所示
  • dst_factor: 指定目标颜色在混合后颜色的权重因子,如下表所示
// 混合颜色计算公式: 
<混合后的颜色> = <源颜色> * src_factor + <目标颜色> * dst_factor

// 一般半透明效果常用如下形式
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)

权重因子列表

(Rs,Gs,Bs,As) 表示源颜色各分量, (Rd,Gd,Bd,Ad) 表示目标颜色的各分量

常量 R分量的系数 G分量的系数 B分量的系数
gl.ZERO 0.0 0.0 0.0
gl.ONE 1.0 1.0 1.0
gl.SRC_COLOR Rs Gs Bs
gl.ONE_MINUS_SRC_COLOR 1-Rs 1-Gs 1-Bs
gl.DST_COLOR Rd Gd Bd
gl.ONE_MINUS_DST_COLOR 1-Rd 1-Gd 1-Bd
gl.SRC_ALPHA As As As
gl.ONE_MINUS_SRC_ALPHA 1-As 1-As 1-As
gl.DST_ALPHA Ad Ad Ad
gl.ONE_MINUS_DST_ALPHA 1-Ad 1-Ad 1-Ad
gl.SRC_ALPHA_SATUREATE min(As,Ad) min(As,Ad) min(As,Ad)

透明和不透明物体共存

实现 a 混合最简单的方式是屏蔽掉隐藏面消除功能,即去掉 gl.enable(gl.DEPTH_TEST),但关闭隐藏面消除功能是一个粗暴的解决方案,并不能满足实际需求。其实可通过某些机制,同时实现隐藏面消除和半透明效果,步骤如下:

//1.开启隐藏面消除功能:
gl.enable(gl.DEPTH_TEST)。

//2.绘制所有不透明的物体(a == 1.0)

//3.锁定深度缓冲区的写入操作,使之只读 (深度缓冲区用于隐藏面消除):
gl.depthMask(false);

//4.绘制所有半透明的物体 a < 1.0,注意将物体按深度排序,a 最小最先绘制

//5.释放深度缓冲区,使之可读可写: 
gl.depthMask(true)

gl.depthMask(mask)

锁定或释放深度缓冲区的写入操作

mask: 锁定深度缓冲区的写入操作 false,释放 true

实现效果

我们写个Demo来实际演示效果,比如我要绘制8个物体,其中前面4个是非透明的物体,即 α 分量值则为1,剩余物体的 α 分量分别从 0.1至0.4不等。

for (var i = 0; i < 8; i++) {
    let color = randomColor();
    color[3] = i > 3 ? (i - 3)/10 :1;// 透明物体 α 分量小于1,非透明物体则等于1
    
    Polygons.push({
        x: random(-9,9),
        y: random(0, 6),
        z: random(-5,5),
        color: color
    });
}

如果是绘制的物体队列是无序的,则必须手动排序。但我这里建立图形时已经排好序,前4个为不透明物体,剩余是透明物体,所以可直接按顺序绘制,针对是否为透明物体,分别设置缓冲区写入和隐藏面删除功能。

if(i < 4){ // 非透明物体
    gl.depthMask(true);
    gl.disable(gl.BLEND);
} else { //透明物体
    gl.depthMask(false);
    gl.enable(gl.BLEND);
    gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
}
drawBufferInfo(gl, vao);

最终完成效果请看:半透明物体和透明物体共存

相关文章

  • WebGL半透明物体的绘制

    WebGL 中当透明和半透明物体共存时,相关设置不正确的话,物体表面会出现破碎杂乱的断面,非常影响效果,我们接着就...

  • WebGL之物体选择

    原文地址: WebGL之物体选择 使用WebGL将图形绘制到画布后,如何与外部进行交互?这其中最关键的就是如何实现...

  • TWaver3D直线、曲线、曲面的绘制

    1. WebGL原生线 WebGL支持绘制点、线、三角;绘制线的方法比较简单,给定顶点,设置绘制方式即可; 假设给...

  • WebGL 绘制Line的bug(一)

    熟悉WebGL的同学都知道,WebGL绘制模式有点、线、面三种;通过点的绘制可以实现粒子系统等,通过线可以绘制一些...

  • webgl入门(一)

    webgl是基于 canvas 进行绘制,通过 getWebGLContext()来获取 webgl 的绘图上下文...

  • 用线段绘制球体(three.js webgl_lines_spe

    用线段绘制球体(three.js webgl_lines_spere例子) Three.js中的webgl_lin...

  • WebGL入门

    初识WebGL 01-手动绘制一个WebGL图形 实现的步骤: 添加一个画布元素 获取到画布元素的基于webgl上...

  • Threejs in autonomous driving -(

    绘制各种几何体是webgl的强项,相反各种异性几何体就非常麻烦。比如圆角矩形来说在webgl中绘制就相对比较麻烦。...

  • WebGL学习(1) — 浏览器支持测试

    什么是WebGL? WebGL是一项用来在网页上绘制和渲染三维图形并允许用户与之交互的技术。同时,WebGL(we...

  • webgl 入门(二)

    webgl 参数传递 webgl是基于着色器进行绘制的.着色器本身无法与 JavaScript 进行通讯以及数据的...

网友评论

    本文标题:WebGL半透明物体的绘制

    本文链接:https://www.haomeiwen.com/subject/lklwnqtx.html