背景知识
这个教程演示了一个3D管线中非常重要的部分-插值,光栅器对从顶点着色器出来的变量所执行的操作。你已经看到了,为了在屏幕上获得一些有意义的东西,你需要指定其中一个从顶点着色器出来的变量为'gl_Position'。这是一个包含了顶点对应坐标的4-向量。向量中的XYZ分量被W分量分割(一个被称为透明切割的过程,在教程中有专门讲解它的课程),接着在标准化格子([-1, 1])之外的任何分量将会被裁剪。结果被转换到屏幕空间坐标,然后三角形(或其他可支持的图元类型)就被光栅器渲染到屏幕上了。
光栅器在三个三角形顶点间执行插值操作(一行接一行或其他方式),然后通过执行片段着色器“访问”三角形内部的每个像素。我们期望片段着色器能返回一个能显示的像素颜色(在通过一些额外的测试后,比如深度测试等),这些像素颜色被光栅器放在颜色缓冲中。其他从顶点着色器从出来的变量(译者注:指那些没有被放在颜色缓冲中,但又必须被渲染出来的变量)都不会通过上面的步骤。如果片段着色器不明确请求这些变量(你可以结合几个片段着色器匹配一个顶点着色器),那么一个通用的驱动优化器将会丢弃在顶点着色器中只是影响这个变量的说明(特殊的着色器程序是顶点着色器和片段着色器的配对组合)。然而,如果片段着色器使用了在光栅化中光栅器插值了的变量,以及每一次片段着色器调用的都是匹配到特定位置的插值了的值。这通常意味着那些紧密相连的像素的值会有些不同(尽管随着三角形越来越远离摄像机这变得无关紧要)。
两个经常依赖插值的很通用的变量是三角形法向量和纹理坐标。顶点法向量经常是被作为包含这个顶点的所有三角形的三角形法向量的平均值计算的。如果物体不完全平坦,这意味着每个三角形的三个顶点法向量是不用于其他三角形的。在这种情况下,我们依靠插值来计算每个特定像素的法向量。这个法向量用于为了呈现更真实的光照效果表现的光照计算。对纹理坐标也是类似的。这些坐标作为模型的一部分被定义在每一个顶点上。为了用纹理“覆盖”三角形,你需要为每个像素执行抽样操作,然后为那个像素指定正确的纹理坐标。这些坐标是插值的结果。
在这个教程中我们会看到通过在三角形表面插不同颜色的值从而看到插值的效果。因为我很懒我们在顶点着色器中生成颜色。一种更乏味的方法是从顶点缓冲中提供它。通常我们不从顶点缓冲中提供颜色。你提供纹理坐标和从一个纹理中抽样颜色。这个颜色稍后会被光照计算处理。
源码演练
out vec4 Color;
参数通过两个管线时必须用'out'保留字以及在着色器全局范围内定义。这个颜色是一个4-向量,因为XYZ分别分量携带RGB值而W为alpha值(像素透明度)。
Color = vec4(clamp(Position, 0.0, 1.0), 1.0);
颜色在图形管线中常常表示为一个范围[0.0, 1.0]间的浮点型点。这个值之后在每一条channel被映射成0~255的整型(共)。我们把顶点颜色值设为一个顶点顶点函数。首先我们使用内置函数clamp()确保我们才能1,-1。如果我们拿这个值作为颜色值,它会被光栅器插值,不过知道X和Y双双超过0否则我们看不到任何东西,因为小于等于0的值会被渲染成黑色。这意味着在颜色超过0变得有意义之前,每个方向半数的边是黑的。通过锁定范围我们仅仅让左下远端为黑色,不过随着我们越来越离开那颜色很快变得明亮许多。尝试把玩clamp函数--完全删除它或改变它的参数,看看效果。
clamp函数的结果对于输出变量来说不完全正确,因为变量是一个4-向量而位置是一个3-向量(clamp并不改变分量的个数,而只是它们的值)。GLSL视图点中也没有默认转换,所以我们必须使它明确。我们用通过用给出的W值串联一个3-向量,来创建一个4-向量的表示法'vec4(vec, W)'。在我们这个例子中,我们使用1.0因为它会去到颜色的alpha部分,我们想要像素完全不透明。
in vec4 Color;
跟在顶点着色器中输出颜色想法,这是在片段着色器中输入颜色。这个变量通过光栅器插值所以每个片段着色器(很可能)执行了不同的颜色。
FragColor = Color;
我们使用插值后的颜色作为不更多修改的片段颜色,以此完成本课程。