webgl自学笔记——深度监测与混合

这一章中关于webgl中颜色的使用我们将深入研究。我们将从研究颜色在webgl和essl中如何被组装和获取开始。然后我们讨论在物体、光照和场景中颜色的使用。这之后我们将看到当一个物体在另一个物体前面是webgl如何来实现物体碰撞,这是通过深度检测来实现的。相反透明度混合允许我们结合所有物体的颜色当一个物体与另一个物体啮合时。我们将用透明度混合来创建透明物体。

这一章主要讨论:

  1. 在物体上使用颜色
  2. 为光源分配颜色
  3. 在ESSL中使用多光源
  4. 深度检测和z缓冲区
  5. 混合方法和公式
  6. 使用face culling来创建透明物体

webgl在RGB颜色模型中还包含第四个属性,这个属性被称为开端通道。扩展后的模型称为RGBA模型,A是为支持alpha。a的取值范围时0.0-1.0,跟其他三个一样。下图代表颜色空间。横轴代表结合rgb能够得到的颜色,纵轴代表alpha通道。

alpha为颜色带来了额外的信息。这个信息影响颜色渲染在屏幕上的方式。通常来说alpha影响颜色的透明度。一般来说我们的颜色都是不透明的,但有一些情况我们得考虑获得半透明颜色。

在webgl 3D场景中我们到处都在使用颜色:

  1. Objects: 3d物体可以通过为每一个顶点选择一个颜色来上色,或者为整个物体选择一个颜色。这通常由材料的diffuse属性决定
  2. Lights:我们可以使用颜色不是白色的环境光和反射光属性。
  3. Scene:场景的背景色可以通过gl.clearColor方法来改变。稍后我们将看到当我们使用透明物体时需要做一些特殊的操作。

·最终的颜色在片元着色器中通过设置特殊的gl_FragColor来得到。如果这个物体的所有片元都拥有同样的颜色,我们可以说这个问题有一个常量颜色。否则这个物体有per-vertex 颜色

Constant coloring

为了获得常量颜色我们把需要得到的颜色放在一个uniform存储器中,这个变量直接传递给片元着色器。这个uniform通常被称为物体的漫反射材料属性。我们也可以结合物体的法线和光源信息来获取Lambert反射系数。我们使用兰伯特系数通过依赖反射光与光源的夹角来改变反射颜色。

下图第一个是没有结合反射系数的物体,第二个是结合反射系数后的颜色。

Per-vertex coloring

在医学和工程可视化应用中,通常能够找到跟他们要渲染的物体的顶点对应的颜色地图。这些地图为每一个顶点分配一个单独的颜色。为了实现per-vertex 着色我们需要在顶点着色器中定义一个attribute来存储顶点的颜色。

attribute vec4 aVertexColor

下一步是将aVertexColor属性分配给一个varying变量,以便能够进入片元着色器中。varying变量是可以被自动插值的。因此每一个片元的颜色都是根据为绕它的顶点的颜色按权重分配的。

如果我们想让我们的颜色地图能够反映光照条件,我们可以让每一个顶点颜色乘以光照的漫反射部分。得到的结果将被分配到可以将它传递到片元着色器的varying变量中。

左侧图片没有反映光源位置信息,右侧图片反映了光源位置信息

Per-fragment coloring

我们可以为每一个像素分配一个随机的颜色,但是ESSL中并没有一个内置的随机数函数。我们可以通过其他方式来获得。这里不展开

注意:当启用alpha通道时需要的是 "attribute vec4 aVertexColor",然后要启用混合功能gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

Use of color in lights

颜色也是光照的属性;在第3章中我们看到光照属性的数量取决于为场景选择的光照模型。比如使用兰伯特反射模型我们只需要一个着色器uniform量:diffuse;相反在Phong反射模型中每一个光源需要拥有三个属性:环境光、漫反射光、镜面光。

(另外,光源位置通常也在着色器中作为一个unifrom变量,以便知道光源位置,所以Phong模型在点位置光源方式中由四个uniform:ambient、diffuse、specular、position;对于方向光这个uniform变量表示的是光源的方向)

Using multiple lights and the scalability problem

Phong反射模型下一个光源需要四个uniform变量,如果我们有多个光源意味着我们需要的uniform会成倍数上升,而每台机器能够获取的最大unifrom数目是有限的;我们可以通过gl.getParameter()中传入gl.MAX_VERTEX_UNIFORM_VECTORS和gl.MAX_FRAGMENT_UNIFORM_VECTORS参数来获取能够使用的最大uniform数目。

Using uniform arrays to handle multiple lights

将多光源的uniform分别存储增加代码量并且难以维护,ESSL中允许我们使用unifrom 数组。这项技术可以允许我们在着色器中引入光照数组来管理多光源。通过这种方式我们可以在着色器总通过便利光照数组来计算光照颜色。虽然我们仍在需要在JavaScript中定义多个光源对象,但是传递给着色器时就变得简单了。

所以在着色器总我们需要定义:

unifrom vec3 uPositionLight[3]

注意:ESSL中不支持动态初始化unifrom 数组

也就意味着我们无法动态创建多光源

然后传递给着色器: