WebGL 第八课 翻译

 

OpenGL第7~8章

裁剪,光栅化和隐藏面消除

光栅化是将对象处理成片元的过程。

必须完成的两件事;第一,使每个集合对象经过图形系统

第二,给颜色缓存中要显示的每个像素附一个颜色值。

图形绘制系统的4个主要任务

建模—>几何处理à光栅化à片元处理à帧缓存

建模:得到一组表示几何对象的顶点数据。

几何处理:作用于顶点数据,确定哪些几何对象会在屏幕上显示,并把灰度值和颜色值赋给对象的顶点。经过一系列的变换矩阵的变换处理

片元处理:只有光栅化之后的片元处理阶段才会用到纹理值,

第8课  合成技术:go over blending

这节课会先浏览一遍合成技术,同时会粗略的看看深度缓存(depth buffer)是怎样工作的。

深度缓存

从第二节课我们知道,当你告诉WebGL去画东西的时候,会有一个大概的过程,

1运行顶点渲染器来计算每个顶点的位置

2在顶点间进行线性插值,来告诉系统哪些片段需要被画。

3对每一个片元运行片段渲染器来计算它的颜色

4写入帧缓存

因此,帧缓存是最后需要被执行的。但是如果要画两个物体呢?例如,如果你画一个中心在(0,0,-5)的正方形和一个中心在(0,0,-10)的正方形,你不会想要画第二个正方形并把第一个覆盖掉,因为它在很远的地方并且应该被覆盖。

WebGL使用深度缓存来处理这种情况。当片元经过片元渲染器处理之后写入帧缓存中,同一般的RGBA颜色值一样,它也会存储一个与片元Z值有关的深度值。

为什么说“与Z值相关”呢?WebGL希望所有的Z值的范围都在0~1之内,0表示最近的(closese)1表示最远的(furthese away)。这些之前都被我们之前在drawScene函数内调用的perspective函数中的投影矩阵隐藏了。到目前你所需要知道的就是Z-buffer值越大,离的越远。这和我们平常的坐标刚好相反(越远Z坐标越小,是负数)。

那么这就是深度缓存了。现在,你可能还记得我们从第一节课就开始用来初始化WebGL上下文的一段代码:

gl.enable(gl.DEPTH_TEST);

这是在告诉系统在把片元写入帧缓存时要做些什么。也就是“注意下深度缓存”。他和另一系统设置the depth function 一起联合使用。它通常有一个默认值,但如果我们要设置它的值的话可以这样设置:

gl.depthFunc(gl.less);

这意味着,“如果我们的片元有一个比当前Z值还要小的Z值,那么就使用新的这个片元,抛弃当前片元。”这些设置及使用它的这些代码就能够为我们提供足够多的behavior了。

合成

合成可以简单的认为是上述过程的另一个选择。我们使用depth function 和depth-testing来决定是否要用新片元替换当前的片元。而如果我们使用合成方法时,我们会用一个合成函数(blending function)来组合当前片元和新片元的颜色并产生一个新的片元,之后把这个新片元写入缓存。

现在我们来看看这段代码。这些代码和上一节课几乎完全相同,所有重要的部分都是在drawScene函数的短的片段里面。首先,我们检查合成复选框是否被选择。

var blending=document.getElementById(“blending”).checked;

如果是,就设置一个用来组合两个片元的函数:

if(blending){

gl.blendFunc(gl.SRC_ALPHA,gl.ONE);

这个函数的参数决定怎样来合成。这需要技巧,但不会很难。第一步,我们先决定两个要求:片元的来源是我们正在画的这个,目标片元是已经在帧缓存。gl.blendFunc的第一个参数决定源因子,第二个决定了目标因子。这些因子是在合成函数中使用的数字。这样,我们就可以说源因子是源片元的alpha值,而目标因子是一个为1的常量。当然也有其他可能,例如,如果你使用SRC_COLOR来确定源的颜色,则源因子的RGBA值就和初始的RGBA组件一样。%>_<%-_-!-_-|||=_=-_-#

假设WebGL试图计算一个片元的颜色(Rd, Gd, Bd, Ad),新来的片元的RGBA值为(Rd, Gd, Bd, Ad);源因子的RGBAz值是(Sr, Sg, Sb, Sa),目标因子的RGBA是(Dr, Dg, Db, Da)。

对于每一个颜色组件,系统将会进行下面这些运算:

Rresult = Rs * Sr + Rd * Dr

Gresult = Gs * Sg + Gd * Dg

Bresult = Bs * Sb + Bd * Db

Aresult = As * Sa + Ad * Da

所以,在这种情况下,我们可以得到(只给出红色组件):

Rresult = Rs * As + Rd

这不是获得透明对象的一个好方法,但是恰好能很好的工作在lighting 的情况下。这一点很值得强调。合成和透明是不同的,他只是一个能够获得透明效果的许多方法中的一个。

好的,现在继续:

gl.enable(gl.BLEND);

如同WebGL中的许多东西一样,合成默认是关掉的,所以我们需要先打开。

gl.disable(gl.DEPTH_TEST);

这个就更有趣了,我们必须先关掉深度测试。不关掉会怎样呢?举个例子,假如我们画一个立方体,如果我们先画背面然后再画正面,这样正面会被合成在背面上来,这就没有问题,但如果我们先画正面,背面由于离我们更远就会在合成之前由于深度测试而被无视掉。

读者们可能会注意到合成对画图的顺序有很大倚赖,这在之前是我们未曾注意的。这个等会儿再说,我们先完成剩下的这些代码:

gl.uniform1f(shaderProgram.alphaUniform, parseFloat(document.getElementById("alpha").value));

在这里我们从JS中获得一个alpha值,并将其导入渲染器中。这是因为我们使用的纹理没有它自己的alpha通道(它只有RGB,所以每一个像素的alpha值都是1)。

drawScene中剩下的就只是一些关掉合成后所要处理的必要代码。

   } else {

      gl.disable(gl.BLEND);

      gl.enable(gl.DEPTH_TEST);

    }

片元渲染器代码中也有一些小的修改以便于使用alpha值。

#ifdef GL_ES

  precision highp float;

  #endif

 

  varying vec2 vTextureCoord;

  varying vec3 vLightWeighting;

 

  uniform float uAlpha;

 

  uniform sampler2D uSampler;

 

  void main(void) {

     vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));

     gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a * uAlpha);

  }

以上就是代码中的所以改变了。

现在回头来看下画图顺序。从这个例子里面我们能得到很好的透明效果,看起来就像真的教堂玻璃一样。现在重新试一下,改变光照方向使方向从Z轴正方向过来——只需要把“-”去掉就行了,看起来也不错,但是真实感完全没有 了。

原因在于在初始光照条件下,立方体背面总是模糊的,也就是说背面的RGB值很小,所以等式:

Rresult = Rs * Ra + Rd

的计算结果就不是那么强烈。也就是说,我们刚好获得了使背面可见性更低的光照。如果我们把光照转到正面,正面的可见性就降低,透明效果就没那么好了。

那么怎样解决这个问题呢?OpenGL FAQ(常见问题)说你需要用一个SRC_ALPHA的源因子,和一个ONE_MINUS_SRC_ALPHA的目标因子。但是由于源片元和目标片元的处理方式的不同,对画图顺序还是会有依赖。

所以用合成来处理透明度是需要技巧的,但如果你可以有效控制场景,就像这节课里控制光源方向,你就可以适当地使用这个功能,当然你需要注意画图顺序。

幸运的是,合成在其他方面还是很有用的,你将会在下节课中看到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值