GLSL 编程/Blender/RGB 立方体
本教程介绍了变化变量。它建立在关于最小着色器的教程之上。
在本教程中,我们将编写一个着色器来渲染一个类似于左侧所示的 RGB 立方体。表面上每个点的颜色由其坐标决定;即,位于位置 的点具有颜色 。例如,点 被映射到颜色 ,即纯蓝色。(这是左侧图形右下角的蓝色角点。)
由于我们要创建一个 RGB 立方体,你首先要按照关于最小着色器的教程中的描述创建立方体网格。继续按照关于最小着色器的教程中的描述创建 Python 脚本和游戏逻辑。
以下是顶点着色器的源代码,您应该将其复制并粘贴到 Python 脚本中对 VertexShader
的赋值。
varying vec4 position;
// this is a varying variable in the vertex shader
void main()
{
position = 0.5 * (gl_Vertex + vec4(1.0, 1.0, 1.0, 0.0));
// Here the vertex shader writes output(!) to the
// varying variable. We add 1.0 to the x, y, and z
// coordinates and multiply by 0.5, because the
// coordinates of the cube are between -1.0 and 1.0
// but we need them between 0.0 and 1.0
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
以下是片段着色器的源代码,应该将其分配给 FragmentShader
varying vec4 position;
// this is a varying variable in the fragment shader
void main()
{
gl_FragColor = position;
// Here the fragment shader reads intput(!) from the
// varying variable. The red, gree, blue, and alpha
// component of the fragment color are set to the
// values in the varying variable. (The alpha
// component of the fragment doesn't matter here.)
}
如果您的立方体没有正确着色,请检查控制台是否有错误消息。
我们着色器的主要任务是在片段着色器中将输出片段颜色 (gl_FragColor
) 设置为在顶点着色器中可用的位置 (gl_Vertex
)。实际上,这并不完全正确:Blender 默认立方体的 gl_Vertex
中的坐标在 -1.0 和 +1.0 之间,而我们希望颜色分量在 0.0 和 1.0 之间;因此,我们需要将 1.0 添加到 x、y 和 z 分量,并将结果乘以 0.5,这由以下表达式完成:0.5 * (gl_Vertex + vec4(1.0, 1.0, 1.0, 0.0))
。
然而,主要问题是:我们如何将顶点着色器中的任何值传递到片段着色器?事实证明,做到这一点的唯一方法是使用变化变量(或简称变化量)。顶点着色器的输出可以写入变化变量,然后片段着色器可以将其作为输入读取。这正是我们需要的。
要指定变化变量,它必须在顶点着色器和片段着色器中以 varying
修饰符(在类型之前)定义,位于任何函数之外;在我们的示例中:varying vec4 position;
。这里是最重要的关于变化变量的规则
顶点着色器中变化变量定义的类型和名称必须与片段着色器中变化变量定义的类型和名称完全匹配,反之亦然。 |
这是为了避免出现 GLSL 编译器无法确定顶点着色器的哪个变化变量应该与片段着色器的哪个变化变量匹配的模糊情况。
RGB 立方体表示可用的颜色集(即显示器的色域)。因此,它也可以用来显示颜色变换的效果。例如,颜色到灰度变换将计算红色、绿色和蓝色颜色分量的平均值,即,然后将此值放入片段颜色的所有三个颜色分量中,以获得相同强度的灰度值。除了平均值,还可以使用相对亮度,即。当然,任何其他颜色变换(改变饱和度、对比度、色调等)也适用。
此着色器的另一种变体可以计算一个 CMY(青色、洋红色、黄色)立方体:对于位置 ,您可以从纯白色中减去与 成比例的红色量,以生成青色。此外,您将减去与 分量成比例的绿色量,以生成洋红色,以及与 成比例的蓝色量,以生成黄色。
如果您真的想变得花哨,您可以计算一个 HSV(色调、饱和度、明度)圆柱体。对于 和 坐标在 -0.5 到 +0.5 之间,您可以获得一个角度 ,在 GLSL 中使用 180.0+degrees(atan(z, x))
介于 0 到 360° 之间,以及一个距离 ,在 0 到 1 之间,从 轴使用 2.0 * sqrt(x * x + z * z)
计算。Blender 内置圆柱体的 坐标在 -1 到 1 之间,可以使用 转换为 0 到 1 之间的值 。关于从 HSV 坐标计算 RGB 颜色的描述,请参见 维基百科上关于 HSV 的文章。
关于变化变量的故事还没有结束。如果您在 **3D 视图** 中选择立方体对象并切换到 **编辑模式**,您将看到它只包含 8 个顶点。因此,顶点着色器可能只被调用 8 次,并且只有 8 个不同的输出被写入变化变量。但是,立方体上还有更多颜色。这是怎么发生的?
答案隐含在 **变化** 变量的名称中。它们之所以被称为变化变量,是因为它们在三角形上变化。(请注意,所有多边形在 OpenGL 中渲染之前都会分解成三角形。)事实上,顶点着色器只为每个三角形的每个顶点调用。如果顶点着色器对不同顶点的变化变量写入不同的值,则这些值会在三角形上插值。然后,片段着色器被调用以处理被三角形覆盖的每个像素,并接收变化变量的插值值。这种插值的详细信息在 “光栅化” 中描述。
如果您想确保片段着色器从顶点着色器接收一个确切的、非插值的变量,您必须确保顶点着色器对三角形的每个顶点写入变化变量的相同值。
本教程到此结束。恭喜!除其他事项外,您已了解到:
- 什么是 RGB 立方体。
- 变化变量的用途以及如何定义它们。
- 顶点着色器写入变化变量的值如何在三角形上插值,然后由片段着色器接收。
如果您想了解更多
- 关于进入和离开顶点和片段着色器的数据流,您应该阅读 “OpenGL ES 2.0 管道” 的描述。
- 关于向量和矩阵操作(例如表达式
0.5 * (gl_Vertex + vec4(1.0, 1.0, 1.0, 0.0))
),您应该阅读 “向量和矩阵操作”。 - 关于变化变量的插值,您应该阅读 “光栅化”。